Spring的AOP思想和实践

来源:互联网 发布:淘宝刷好评兼职平台 编辑:程序博客网 时间:2024/05/21 19:36

引言

       大家都知道Spring中最最牛逼的就是IOC/DI :控制反转/依赖注入,AOP: 面向切面编程,两个核心,如果说Spring是一个牛逼的框架,不如它是一个思想的引导者,Spring中思想很重要,条例整清楚了,即便是记不住其中的API,但是只要看到,便有一种水到渠成的感觉。

       再次认识到,学习是一个需要不断反复的过程,不论当初记的有多深刻,只要一段时间不用不看,很快就会忘记,所以在此记录学习的过程,希望日后多来看看,相信会有记住的一天!

       下面是学习spring中AOP的一些笔记,从底层到企业中的应用,一步一个脚印,一步一个Demo


一:因为spring中AOP应用的是代理,所以先来复习一下代理的知识


  JDK动态代理

/** * 代理类接口 * @author zhaofx * */public interface DogService {public void run();public void eat();}

/** * 被代理类实现 * @author zhaofx * */public class DogServiceImpl implements DogService{@Overridepublic void run(){System.out.println("dog...run。。。。");}@Overridepublic void eat() {System.out.println("dog...eat。。。。");}}

/** * JDK动态代理,被代理类必须有接口 */@Testpublic void test2(){final DogService dogService = new DogServiceImpl();/** * @Param:类加载器,jdk提供三种类加载器 * @Param:被代理类的接口,JDK动态代理必须要有接口 * @Param:此处是一个匿名内部类,也可以是一个Implement(实现)了InvocationHandler接口的子类对象 */DogService dogServiceProxy = (DogService)Proxy.newProxyInstance(TestAop.class.getClassLoader(),dogService.getClass().getInterfaces() , new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {System.out.println("方法前增强。。。。");//***切记,此处第一个参数应该是被代理对象,而非代理后proxy 对象,如果填proxy将不限循环,一直执行已经被代理的方法method.invoke(dogService, args);System.out.println("方法后增强");return proxy;}});dogServiceProxy.run();//**** getClass 方法永远不会被代理,通过这个方法可以看到此对象是被代理点对象,并且是JDK动态代理的System.out.println(dogServiceProxy.getClass());}

方法前增强。。。。
dog...run。。。。
方法后增强

class $Proxy4


 CGlib动态代理

/** * CGlib动态代理 * 和JDK动态代理最大的区别是 CGlib代理,被代理类可以没有接口 *  */@Testpublic void test3(){final DogServiceImpl dogServiceImpl = new DogServiceImpl();Enhancer enhancer = new Enhancer();enhancer.setSuperclass(dogServiceImpl.getClass());enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object proxy, Method method, Object[] arg,MethodProxy methodProxy) throws Throwable {System.out.println("方法前增强");methodProxy.invoke(dogServiceImpl, arg);System.out.println("方法后增强");method.invoke(dogServiceImpl, arg); //此method是原生method不增强return proxy;}});DogServiceImpl dogServiceImpl2 = (DogServiceImpl) enhancer.create();dogServiceImpl2.run();//**** getClass 方法永远不会被代理,通过这个方法可以看到此对象是被代理点对象,并且是用CGlib代理的System.out.println(dogServiceImpl2.getClass());}

方法前增强
dog...run。。。。
方法后增强
dog...run。。。。
class cn.aop.service.impl.DogServiceImpl $  $ EnhancerByCGLIB$$8530829c

使用ProxyFactoryBean代理目标类所有方法,太死

/** * MethodBeforeAdvice 为前置通知 * @author zhaofx * */public class DogAdvice  implements MethodBeforeAdvice{@Overridepublic void before(Method method, Object[] args, Object target)throws Throwable {System.out.println("before.....");}}

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="   http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans.xsd">   <!--    用 Spring的ProxyFactoryBean代理Bean ,此方式只能代理目标Bean的所有方法,   并且目标Bean需要一个个配置到ProxyFactoryBean代理Bean工厂下    --> <!-- 被代理的类 --><bean id="dogService" class="cn.aop.service.impl.DogServiceImpl"></bean><!-- 代理类回调方法,也称为执行句柄,或者通知  --><bean id="methodBefore" class="cn.aop.advice.DogAdvice"></bean>   <!-- 生成代理对象 --><!-- 这是一个advice,也是一个advisor ,对所有方法增强增强,正常情况下  advisor = advice + pointCut --><bean id="dogBeanFactory" class="org.springframework.aop.framework.ProxyFactoryBean"><!-- 被代理类接口,可以没有,(如果接口使用cglib代理,如有有使用jdk动态代理,没有证实) --><property name="proxyInterfaces" value="cn.aop.service.DogService"></property><!-- 通知advisor --><property name="interceptorNames" value="methodBefore"></property><!--被代理的类  --><property name="target" ref="dogService"></property></bean></beans>

/** * Spring AOP 最底层的AOP例子  ProxyFactoryBean代理Bean */@Testpublic void test1(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_aop.xml");DogService dogService = context.getBean("dogBeanFactory", DogService.class);dogService.run();System.out.println(dogService.getClass());}

before.....
dog...run。。。。

class $Proxy4


使用ProxyFactoryBean代理目标类可选方法,正则匹配

package cn.aop.advice;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;/** * MethodInterceptor  环绕通知 * @author zhzofx */public class AroundDogAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation methodInvocation) throws Throwable {System.out.println("方法前增强around。。。");Object obj = methodInvocation.proceed();System.out.println("方法后增强around。。。");return obj;}}

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="   http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 被代理的类 --><bean id="dogService" class="cn.aop.service.impl.DogServiceImpl"></bean><!-- 代理类回调方法(环绕通知) --><bean id="aroundDogAdvice" class="cn.aop.advice.AroundDogAdvice"></bean><!-- 这是一个advisor,带有切点的切面advisor --><bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><property name="advice" ref="aroundDogAdvice"></property><property name="patterns" value=".*run.*"></property></bean><bean id="regexpProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"><!--jdk 或者 CGlib 。你懂的,可有可无  --><property name="proxyInterfaces" value="cn.aop.service.DogService"></property><!-- 此处 是value,不是  ref  --><property name="interceptorNames" value="regexpAdvisor"></property><!-- 指向被代理类,需要将被代理类配置到这,繁琐。 --><property name="target" ref="dogService"></property></bean></beans>

/** * 通过正则表达式对被代理类的方法进行增强,可以只对某些方法进行增强 */@Testpublic void test4(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_aop.xml");DogService dogService = context.getBean("regexpProxyFactoryBean", DogService.class);dogService.run();}

方法前增强around。。。
dog...run。。。。

方法后增强around。。。


使用BeanNameAutoProxyCreator根据正则匹配所有Bean加入AOP代理

/** * AfterReturningAdvice  后置通知 * @author zhzofx * */public class AfterAdvice implements AfterReturningAdvice{@Overridepublic void afterReturning(Object returnValue, Method method,Object[] args, Object target) throws Throwable {System.out.println("执行后增强。。。");}}

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="   http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 被代理的类 --><bean id="dogService" class="cn.aop.service.impl.DogServiceImpl"></bean><bean id="catService" class="cn.aop.service.impl.CatServiceImpl"></bean><!-- 通知 --><bean id="afterAdvice" class="cn.aop.advice.AfterAdvice"></bean><!-- 自动扫描代理bean , 对Bean的所有方法进行拦截 之前的做法都需要从ProxyFactory中获取对象,通过这种方式可以直接获取xml中配置的被代理bean,不现在必再从工厂中获取, 可以直接取dogService,返回的就是增强的代理类  --><bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><!-- 被拦截代理的bean , 拦截id 以Service结尾的Bean--><property name="beanNames" value="*Service"></property><!-- 通知 --><property name="interceptorNames" value="afterAdvice"></property></bean></beans>

/** * 自动扫描,对所有配置Bean都进行代理增强,不能精确到方法 */@Testpublic void test5(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_aop.xml");DogService dogService = context.getBean("dogService", DogService.class);dogService.run();CatService catService = context.getBean("catService", CatService.class);catService.run();}

dog...run。。。。
执行后增强。。。
cat,,run....
执行后增强。。。




1 0