1,动态代理,指的是通过一个代理对象创建需要的业务对象,然后在这个代理对象中统一进行各种操作。
步骤:
1)写一个类实现InvocationHandler接口;
2)创建要代理的对象
2,创建一个简单的打印日志的类Logger
package com.yangw.spring.proxy; import java.util.Date; public class Logger { public static void info(String msg){ System.out.println(new Date()+"----"+msg); } }
3,自定义注解类
package com.yangw.spring.model; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface LogInfo { public String value() default ""; }
4,自定义动态代理类LogProxy
package com.yangw.spring.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import com.yangw.spring.model.LogInfo; /** * 1 写一个类,实现InvocationHandler接口 * @author Administrator * */ public class LogProxy implements InvocationHandler { //2,创建代理对象 private Object target; private LogProxy(){}; //3,创建一个方法来生成代理对象,这个方法的参数是要代理的对象 public static Object getInstance(Object obj){ //3.1 创建LogProxy对象 LogProxy proxy=new LogProxy(); //3.2 设置代理对象 proxy.target=obj; //3.3 通过Proxy.newProxyInstance()创建代理对象 //参数1:要代理对象的classloader,参数2:要代理对象的实现的所有接口, //参数3:实现InvocationHandler接口的对象 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), proxy); } /** * 当有了代理对象之后,都会调用下面的invoke()方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //这里怎么处理完全由我们来控制的 /*if(method.getName().equals("add")|| method.getName().equals("delete")){ Logger.info("调用我..."); }*/ //只对有LogInfo注解的进行处理, //而且是在method.invoke调用之前,调用之后执行都可以 //在异常中进行处理也可以 if(method.isAnnotationPresent(LogInfo.class)){ Logger.info(method.getAnnotation(LogInfo.class).value()); } return method.invoke(target, args); //aspect orient program (面向切面编程) } }
5,在需要加入注解的接口上面加入自定义注解LogInfo
package com.yangw.spring.dao; import com.yangw.spring.model.LogInfo; import com.yangw.spring.model.User; public interface IUserDao { @LogInfo("add a user") public void add(User user) ; @LogInfo("delete a user") public void delete(int id) ; public User load(int id); }
6,beans2.xml中的配置如下
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!--1, 打开Spring的annotation --> <context:annotation-config/> <!-- 2, 设定Spring去那些包中找annotation --> <context:component-scan base-package="com.yangw.spring" /> <!--用代理类实现 对于静态(static)的注入,使用factory-method --> <bean id="userDynamicDao" class="com.yangw.spring.proxy.LogProxy" factory-method="getInstance"> <!--静态方法传入的参数 --> <constructor-arg ref="userDao" /> </bean> <!-- 依次加入想加入的 <bean id="msgDynamicDao" class="com.yangw.spring.proxy.LogProxy" factory-method="getInstance"> <constructor-arg ref="MsgDao" /> </bean> --> </beans>
7,UserService类上注入userDynamicDao
package com.yangw.spring.service; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.yangw.spring.dao.IUserDao; import com.yangw.spring.model.User; @Service("userService") public class UserService implements IUserService { @Resource(name="userDynamicDao") private IUserDao userDao ; @Override public void add(User user) { userDao.add(user); } @Override public void delete(int id) { userDao.delete(id); } @Override public User load(int id) { return userDao.load(id); } }
7, 测试
package com.yangw.spring.test; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.yangw.spring.action.UserAction; import com.yangw.spring.model.User; public class TestSpring { //1,创建Spring工厂 BeanFactory factory= new ClassPathXmlApplicationContext("beans2.xml"); @Test public void testUser(){ //2,通过工厂获取Spring的对象 UserAction userAction = factory.getBean("userAction", UserAction.class); User u1=new User(1,"yangw"); userAction.setUser(u1); userAction.add(); userAction.delete(); userAction.load(); } }
8, Spring实现动态代理(基于annotation方式)
导入aopalliance-1.0.jar aspectjrt-1.6.10.jar aspectjweaver-1.7.2.jar 三个包,Spring使用这三个包实现AOP
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--1, 打开Spring的annotation --> <context:annotation-config/> <!-- 2, 设定Spring去那些包中找annotation --> <context:component-scan base-package="com.yangw.spring" /> <!-- 打开基于annotation的aop自动代理 --> <aop:aspectj-autoproxy /> </beans>
切面类
package com.yangw.spring.proxy; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component("logAspect") //交给Spring管理 @Aspect //说明是一个切面类 public class LogAspect { //前置通知 // 第1个"*": 任意返回值 // 第2个"*": com.yangw.spring.dao包中的所有类 // 第3个"*": add*表示以add开头的所有方法 // "(..)" : 表示方法参数是任意值 // "||" : 可以用或表达式加入多个条件 /** * 函数调用之前执行 */ @Before("execution(* com.yangw.spring.dao.*.add*(..))||" +"execution(* com.yangw.spring.dao.*.delete*(..))||" +"execution(* com.yangw.spring.dao.*.update*(..))") public void logStart(JoinPoint jp){ System.out.println(jp.getTarget()); //得到执行的类 System.out.println(jp.getSignature().getName()); //得到执行的方法名 Logger.info("log start."); } /** * 函数调用之后执行 */ @After("execution(* com.yangw.spring.dao.*.add*(..))||" +"execution(* com.yangw.spring.dao.*.delete*(..))||" +"execution(* com.yangw.spring.dao.*.update*(..))") public void logEnd(JoinPoint jp){ System.out.println(jp.getTarget()); //得到执行的类 System.out.println(jp.getSignature().getName()); //得到执行的方法名 Logger.info("log end."); } /** * 函数调用过程中执行 */ @Around("execution(* com.yangw.spring.dao.*.add*(..))||" +"execution(* com.yangw.spring.dao.*.delete*(..))||" +"execution(* com.yangw.spring.dao.*.update*(..))") public void logAround(ProceedingJoinPoint pjp) throws Throwable{ Logger.info("log around start"); pjp.proceed(); //让程序往下执行 Logger.info("log around end."); } }
测试
package com.yangw.spring.test; import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.yangw.spring.action.UserAction; import com.yangw.spring.model.User; public class TestSpring { //1,创建Spring工厂 BeanFactory factory= new ClassPathXmlApplicationContext("beans3.xml"); @Test public void testUser(){ //2,通过工厂获取Spring的对象 UserAction userAction = factory.getBean("userAction", UserAction.class); User u1=new User(1,"yangw"); userAction.setUser(u1); userAction.add(); userAction.delete(); userAction.load(); } }
测试结果
Mon Oct 21 19:13:29 CST 2013----log around start com.yangw.spring.dao.UserDao@18ce14a add Mon Oct 21 19:13:29 CST 2013----log start. add :User [id=1, username=yangw] Mon Oct 21 19:13:29 CST 2013----log around end. com.yangw.spring.dao.UserDao@18ce14a add Mon Oct 21 19:13:29 CST 2013----log end. Mon Oct 21 19:13:29 CST 2013----log around start com.yangw.spring.dao.UserDao@18ce14a delete Mon Oct 21 19:13:29 CST 2013----log start. delete :0 Mon Oct 21 19:13:29 CST 2013----log around end. com.yangw.spring.dao.UserDao@18ce14a delete Mon Oct 21 19:13:29 CST 2013----log end. load :0 null
9, Spring实现动态代理(基于xml方式) 一般这种用的多
导入aopalliance-1.0.jar aspectjrt-1.6.10.jar aspectjweaver-1.7.2.jar 三个包,Spring使用这三个包实现AOP
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--1, 打开Spring的annotation --> <context:annotation-config/> <!-- 2, 设定Spring去那些包中找annotation --> <context:component-scan base-package="com.yangw.spring" /> <aop:config> <!-- 定义切面 --> <aop:aspect id="myLogAspect" ref="logAspect"> <!-- 在哪些位置加入相应的Aspect--> <aop:pointcut id="logPointCut" expression="execution(* com.yangw.spring.dao.*.add*(..))|| execution(* com.yangw.spring.dao.*.delete*(..))|| execution(* com.yangw.spring.dao.*.update*(..))" /> <!-- 定义通知 --> <aop:before method="logStart" pointcut-ref="logPointCut"/> <aop:after method="logEnd" pointcut-ref="logPointCut"/> <aop:around method="logAround" pointcut-ref="logPointCut"/> </aop:aspect> </aop:config> </beans>
package com.yangw.spring.proxy; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.springframework.stereotype.Component; @Component("logAspect") //交给Spring管理 public class LogAspect1 { public void logStart(JoinPoint jp){ System.out.println(jp.getTarget()); //得到执行的类 System.out.println(jp.getSignature().getName()); //得到执行的方法名 Logger.info("log start."); } public void logEnd(JoinPoint jp){ System.out.println(jp.getTarget()); //得到执行的类 System.out.println(jp.getSignature().getName()); //得到执行的方法名 Logger.info("log end."); } public void logAround(ProceedingJoinPoint pjp) throws Throwable{ Logger.info("log around start"); pjp.proceed(); //让程序往下执行 Logger.info("log around end."); } }
测试和结果与前面的基于annotation的一模一样,不在赘述!