AOP的简称"Aspect Oriented Programing"的简称———面向切面编程。java
一个类或者一段程序代码用于一些具备边界性质的特性的特定点。这些代码的特定点就被成为"链接点"。Spring只支持方法的链接点,即仅能在方法调用前,方法调用后,方法抛出异常时及方法调用后这些程序执行点织入加强。链接点由两个信息肯定: 1.用方法表示的程序执行点 2.用相对于位置表示方位。 例如: demo.foo()方法执行器的链接点,执行点未demo.foo(),方位未改方法执行前的位置。Spring使用切点对执行点进行定位,而方位装载加强类型中定义。正则表达式
每一个程序类都用于多个连系欸但,若是一个用于两个方法的类,这两个方法都是链接点,链接点是客观存在的事务。AOP经过"切点"定位特定的链接点。切点和链接点是一对多的关系(就像数据库查询条件和记录的关系)。在Spring中,切点使用org.springframework.aop.Pointcut接口进行描述,它使用类和方法做为链接点的查询条件,Spring AOP的规则系欸性能引发负责系欸性能切点所设定的查询条件,找到对应的链接点。链接点是方法执行前,执行后等包括方位信息的具体程序执行点,而切点值定位到某个方法上,因此若是但愿定位到具体的链接点上,还须要提供方位信息.spring
加强是织入目标类链接点上的一段程序代码,结合执行段的方位信息和切点信息,就能够找到特定的链接。真正的加强及包括用于添加到目标链接点上的一段执行逻辑,由包含用于定位链接点的方位信息,因此Spring所提供的加强接口的都是带方位名的。因此Spring所提供的加强接口都是带方位名的,例如BeforeAdvice,AfterReturningAdvice,ThrowsAdvice等。只有结合了切点和加强,才能肯定特定的链接点并实施加强逻辑。数据库
加强逻辑的织入目标类。若是没有AOP,那么目标业务须要本身实现全部的逻辑,在AOP的帮助下,那些非横切的逻辑的程序逻辑,而性能监视和事务管理等这些横切的逻辑则可使用AOP的动态织入特定的链接点上。编程
引介是一种特护的加强,它为类添加一些属性和方法。这样,几时一个业务类本来没有实现某个接口,经过AOP的引介功能,也能够动态地位改业务类添加接口地实现逻辑,让业务类成为这个接口地实现类。框架
织入是将加强添加到慕白哦类地具体链接点上。AOP就像一台织布机,将目标类,曾倩或者引介完美无缺地编织到一块儿。AOP有三种织入方式: 1.编译期织入,这个要求使用特殊地Java编译器。 2.类装载期织入,这个要求使用特殊地类装器。 动态代理,在运行期位目标类添加加强生产子类地方式。 Spring采用了动态代理地织入,而AspectJ采用编译期织入和类装载期织入。ide
一个类被AOP织入加强以后,就产生了一个结果类,它是融合了袁磊和曾倩逻辑地代理类。根据不一样地代理方式,代理多是ihe袁磊具备相同接口地类,也多是原类地子类。,因此能够采用于调用原类相同地方式调用代理类。性能
切面有切点和曾倩(引介)组成,它既包括横切逻辑地定义,也包括了链接点地定义。Spring AOP就是负责实施切面地框架,它将切面所定义地横切逻辑织入切面所指定的链接点中。测试
JDK的动态代理主题要涉及java.lang.reflect包下面的java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。其中,java.lang.reflect.InvocationHandler是一个接口,能够i经过实现接口定义很且逻辑,并经过反射机制调用目标类代码,动态地将横切逻辑和业务逻辑编制在一块儿。Proxy利用了InvocationHandler动态建立一个符合某一接口地实例. 例子: 实现InvocationHandlerflex
public class JdkProxy implements InvocationHandler { private Object target; public JdkProxy(Object target) { this.target = target; } [@Override](https://my.oschina.net/u/1162528) public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { PerformanceMonitor.begin(target.getClass().getName()+"."+method.getName()); Object invoke = method.invoke(target, args); PerformanceMonitor.end(); return invoke; } }
测试代码: System.out.println("-------------------使用jdk动态代理------------------"); JdkProxy jdkProxy = new JdkProxy(forumService); ForumService instance = (ForumService) Proxy.newProxyInstance(Demo.class.getClassLoader(), new Class[]{ForumService.class}, jdkProxy); instance.removeForum(1); 执行结果:
使用JDK建立地代理有一个限制,它只能位接口建立一个代理实例,这一点能够从Proxy地接口方法public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)中看出来。第二个参数就是接口须要代理实例实现的接口列表。CGLib采用了底层的字节码技术,能够位一个类建立一个子类,在子类中采用方法拦击的技术拦截因此父类方法调用并顺势织入很且逻辑。下面采用CGLib技术编写一个能够位任何类建立织入性能键事横切逻辑代理对象的代理建立器。
实例:
public class CglibProxy implements MethodInterceptor { Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz) { enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } [@Override](https://my.oschina.net/u/1162528) public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { PerformanceMonitor.begin(o.getClass().getName()+"."+method.getName()); Object invoke = methodProxy.invokeSuper(o, objects); PerformanceMonitor.end(); return invoke; } }
用户经过getProxy(Class clazz)为一个类建立代理对象,该对象扩展clazz实现代理,在这个代理对象中,织入性能监视得横切逻辑。intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)是CGLib定义的intercept接口方法,它拦截了因此目标类方法的调用。o:目标类实例,method:目标了方法的反射对象,args:方法的动态入参,proxy:代理实例。
测试代码:
System.out.println("-------------------使用CGLib动态代理------------------"); CglibProxy cglibProxy = new CglibProxy(); ForumServiceImpl forumService1 = (ForumServiceImpl)cglibProxy.getProxy(ForumServiceImpl.class); forumService1.removeForum(1);
执行结果:
AOP联盟是众多开源开源AOP项目的联合组织,该组织的目的是为了制定一套规范的AOP标准,定义标准的AOP接口。以便遵照标准的具体实现能够互相调用。
Spring只支持方法的加强,加强既包含横切逻辑,又包括部分连接点的信息。
AOP联盟为加强定义了Advice接口,Sring支持5种类型的加强,加强的接口集成关系图以下:
1.前置加强:org.springframework.aop.BeforeAdvice是为扩展而用,org.springframework.aop.MethodBeforeAdvice是目前可用的前置加强。
2.后置加强:org.springframework.aop.AfterReturningAdvice表明后置加强,表示在目标方法执行后实施加强。
3.环绕加强:org.aopalliance.intercept.MethodInterceptor表明环绕加强,表示在目标方法的执行先后实施加强。
4.异常抛出加强:org.springframework.aop.ThrowsAdvice表明抛出异常加强,表示在目标类种添加一些新的方法和属性。
5.引介加强:org.springframework.aop.IntroductionInterceptor表明引介加强,表示在目标类种添加一些新的方法和属性。
MethodBeforeAdvice是BeforeAdvice前置的加强接口子类,BeforeAdvice存在的意义是为了后续的扩展。 void before(Method method, Object[] args, Object target) throws Throwable是MethodBeforeAdvice接口的惟一方法,method是目标放啊,args目标方法的参数,target为目标类实例。该方法发生异常的时候将阻止目标类方法执行。
实例: Waiter.java普通服务员
public interface Waiter { void greetTo(String name); void serveTo(String name); }
PoliteWaiter.java礼貌地服务员
public class PoliteWaiter implements Waiter { [@Override](https://my.oschina.net/u/1162528) public void greetTo(String name) { System.out.println("greet to "+name+"...."); } [@Override](https://my.oschina.net/u/1162528) public void serveTo(String name) { System.out.println("serve to "+name+"...."); } }
GreetBeforeAdvice.java 前置加强
public class GreetBeforeAdvice implements MethodBeforeAdvice { [@Override](https://my.oschina.net/u/1162528) public void before(Method method, Object[] objects, Object o) throws Throwable { String clientName = (String)objects[0]; System.out.println("How are you! Mr."+clientName); } }
测试代码:
Waiter target = new PoliteWaiter(); BeforeAdvice advice = new GreetBeforeAdvice(); //Spring提供的代理工厂 ProxyFactory proxyFactory = new ProxyFactory(); //设置代理目标 proxyFactory.setTarget(target); proxyFactory.addAdvice(advice); Waiter proxy = (Waiter) proxyFactory.getProxy(); proxy.greetTo("John"); proxy.serveTo("jack");
ProxyFactory 在上面的例子中咱们使用了ProxyFactory,ProxyFactory实际上使用的是JDK和CGLib动态代理技术将加强应用到目标类中。 ![] CglibAopProxy使用的是CGLib动态代理技术,JdkDynamicAopProxy使用的是JDK动态代理技术建立代理。若是经过ProxyFactory的setInterfaces(Class[] interfaces)方法指定目标接口进行代理,就是要JdkDynamicAopProxy,若是针对的是类的代理,就使用CglibAopProxy,可使用ProxyFactory的setOptimize(true)方法让ProxyFactory启动u欧化代理的方式,此时针对接口的代理也是使用CglibAopProxy。
//使用CGLib代理的方式 proxyFactory.setOptimize(true);
//使用的jdk代理的方式 proxyFactory.setInterfaces(target.getClass().getInterfaces());
使用配置文件的方式:
<bean id="greetingAdvice" class="com.flexible.beforeadvice.GreetBeforeAdvice"></bean> <bean id="target" class="com.flexible.beforeadvice.PoliteWaiter"></bean> <bean id="waiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.flexible.beforeadvice.Waiter" p:interceptorNames="greetingAdvice" p:target-ref="target"> </bean>
测试代码:
@Test public void testMethod1(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("waiter"); waiter.greetTo("zhangsgan "); waiter.serveTo("李四"); }
ProxyFactoryBean是FactoryBean接口的实现类,它负责实例化一个Bean。ProxyFactoryBean负责为其余的Bean建立代理实例,它在内部使用ProxyFactory来完成这项工做。ProxyFactoryBean的几个经常使用的可配置属性。
1.target:代理的目标对象。
2.proxyInterfaces:代理所须要实现的接口,能够是多个接口。该属性还有一个别名属性interfaces
3.interceptorNames:须要织入目标对象的Bean列表,采用Bean的名曾指定,这些Bean必须实现了org.springframework.cglib.proxy.MethodInterceptor接口或者org.springframework.aop.Advisor的Bean,配置中的顺序的应调用的顺序。
4.sigleton:返回的代理是不是单实例,默认为单实例。
5.optimize:默认是false,使用的是jdk动态代理建立代理,若是设置true,强制使用CGLib动态代理,对于singleton代理,推荐使用CGLib。
6.proxyTargetClass:是否对类进行代理(而不是对接口进行代理)。设置为true时,使用的CGLib动态代理。
后置加强在目标类方法调用后执行。
GreetAfterAdvice.java
public class GreetAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("please enjoy yourself...."); } }
beans.xml
<bean id="target2" class="com.flexible.afteradvice.PoliteWaiter"></bean> <bean id="greetingAdvice2" class="com.flexible.afteradvice.GreetBeforeAdvice"></bean> <bean id="greetingAfterAdvice" class="com.flexible.afteradvice.GreetAfterAdvice"></bean> <bean id="waiter2" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.flexible.afteradvice.Waiter" p:interceptorNames="greetingAdvice2,greetingAfterAdvice" p:optimize="true" p:target-ref="target2"> </bean>
测试代码:
@Test public void testMethod1(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("waiter2"); waiter.greetTo("zhangsgan "); waiter.serveTo("李四"); }
执行结果:
How are you! Mr.zhangsgan greet to zhangsgan .... please enjoy yourself.... How are you! Mr.李四 serve to 李四.... please enjoy yourself....
环绕加强容许在目标类方法调用先后织入横切逻辑,综合了前置和后置加强功能。
例子: GreetingInterceptor.java
public class GreetingInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { Object[] args =methodInvocation.getArguments(); String clientNme = (String) args[0]; System.out.println("How are you Mr."+clientNme+"...."); Object proceed = methodInvocation.proceed(); System.out.println("Please enjoy yourself...."); return proceed; } }
bean.xml
<bean id="target3" class="com.flexible.aroundadvice.PoliteWaiter"></bean> <bean id="greetingAdvice3" class="com.flexible.aroundadvice.GreetingInterceptor"></bean> <bean id="waiter3" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="com.flexible.aroundadvice.Waiter" p:interceptorNames="greetingAdvice3" p:target-ref="target3"> </bean>
测试代码:
@Test public void testMethod1(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("waiter3"); waiter.greetTo("zhangsgan "); waiter.serveTo("李四"); }
测试结果
How are you Mr.zhangsgan .... greet to zhangsgan .... Please enjoy yourself.... How are you Mr.李四.... serve to 李四.... Please enjoy yourself....
异常抛出加强最适合的应用场景时事务管理,当参与事务的某个DAO发生异常时,事务管理器就必须回滚事务。要定义异常加强须要实现业务ThrowsAdvice加强,该接口只是一个标签接口,在运行期间,Spring使用反射机制自行判断,必须使用下面的形式定义方法
public void afterThrowing(Method method,Object[] args,Object target,Exception ex){
PayService.java 业务类 /** * 模拟业务的类,支付的时候抛出异常 */ public class PayService {
public void payMony(String from, double money, String to) { //TODO -- TODO some thing throw new RuntimeException("测试抛出运行时异常...."); } }
beans.xml 配置
<bean id="transactionManager" class="com.flexible.throwadvice.TransactionManager"></bean> <bean id="payTarget" class="com.flexible.throwadvice.PayService"></bean> <bean id="ins" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="transactionManager" p:target-ref="payTarget" p:proxyTargetClass="true"> </bean>
测试代码:
@Test public void testMethod1(){ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); PayService payService = (PayService) context.getBean("ins"); payService.payMony("1",100.00,"2"); }
测试结果:
method:payMony 抛出异常:测试抛出运行时异常.... 成功回滚事务
引介加强时一种比较特殊的加强类型,它不是在目标方法加强,而是为目标类建立新的方法和属性,因此介加强的链接点是类级别的。而非方法级别的。经过引介加强,能够为目标类添加一个接口的实现,即原来的目标类的为实现某个接口,经过引介加强能够为目标了常见实现某个接口的代理。Spring 定义了引介加强接口IntroductionInterceptor,该接口没有定义任何方法,Spring为该接口提供了DelegatingIntroductionInterceptor实现类。通常状况下,经过扩展该实现类定义本身引介加强类。
若是咱们须要有选择地织入目标类地某些特定地方法中,就须要使用切点进行目标链接点的定位。描述连系欸可是进行AOP编程最主要的工做。加强的提供了连系欸但方法为信息,切点进一步的描述了织入哪些类的哪些方法上。 Spirng经过org.springframework.aop.Pointcut接口秒速和切点,其中org.springframework.aop.Pointcut是由ClassFilter和MethodMatcher构成,经过ClassFilter定位到某些特定类上,经过MethodMatcher定位到某些特定方法上。这样org.springframework.aop.Pointcut就可以定位某些类的某些方法上的能力。org.springframework.aop.Pointcut的关系结构图以下:
ClassFilter只定义了一个方法matcher(Class clazz),其参数表明一个被检测类,改方法判别被u检测的类是否匹配过滤条件。 Spring支持两种匹配器:
1.静态匹配器(仅须要匹配一次,对方法签名进行匹配)
2.动态匹配器(由于可能每次入参都不同,须要每次调用都检测,影响性能,通常不常使用),方法匹配器的类型由isRuntime()方法返回值决定,false表示静态匹配器,true表示动态匹配器。
1.静态方法切点:org.springframework.aop.support.StaticMethodMatcherPointcut是静态方法切点的抽象类,默认状况下它匹配因此的类。org.springframework.aop.support.StaticMethodMatcherPointcut的子类有:org.springframework.aop.support.NameMatchMethodPointcut和org.springframework.aop.support.AbstractRegexpMethodPointcut,NameMatchMethodPointcut提供简单字符串匹配签名,AbstractRegexpMethodPointcut使用正则表达式匹配放啊签名。
2.动态方法切点:org.springframework.aop.support.DynamicMethodMatcherPointcut是动态方法切点的抽象基类,默认状况下匹配全部类。
3.注解切点:org.springframework.aop.support.annotation.AnnotationMatchingPointcut实现类表示注解其欸但。使用AnnotationMatchingPointcut支持在BEAN中直接经过Java5.0注解标签订义的切点。
4.表达式切点:org.springframework.aop.support.ExpressionPointcut接口主要为了支持AspectJ切点表达式语法而定义的接口。
5.流程切点:org.springframework.aop.support.ControlFlowPointcut实现类表示控制流程切点。ControlFlowPointcut是一种特殊的的切点,它根据程序执行堆栈信息的查看目标方法是否由某一个方法直接或者看法的发起调用,以此判断是否为匹配的链接点。
6.复合切点:org.springframework.aop.support.ComposablePointcut实现类是为了建立多个切点而提供的方便操做类。它全部的方法都返回ComposablePointcut类,这样就可使用连接表达式对切点进行操做:Pointcut pc = new ComposablePointcut().union(classFilter).intersetion(methodMatcher).intersetion(pointcut).
因为加强既包含横切代码,又包含部分链接点的部分信息(方法前,方法后主方为信息),能够进经过加强类生成一个切面。可是切点仅表明目标类连系欸但那的部分信息(类和方法的定位),全部仅有切点没法制做出一个切面,必须结合加强才能制做出切面。Spring使用org.springframework.aop.Advisor接口比埃是切面的概念,一个切面同时包含横切代码和链接点信息。切面能够分为三类:
1.Advisor:表明通常切面,仅包含一个Advice。由于Advice包含了横切代码和链接点信息,全部Advice自己就是一个简单的切面,它表明的横切的链接点是全部目标类的全部方法,由于这个横切面很宽泛,通常状况下不使用。
2.PointcutAdvisor:表明具备切点的切面,包含Advice和Pointcut两个类,这样就能够经过类,方法名及方法方位等信息灵活的定义切面的连接点,提供更具使用行的切面。
PointcutAdvisor主要有6个具体的实现类。 1.DefaultPointcutdvisor:最经常使用的切面类型,它能够经过任意Pointcut和Advice定义一个切面,惟一不支持的是引介的切面类型,通常能够经过扩展改类实现自定义的的切面。
2.NameMatchMethodPointcutAdvisor:经过类能够定义按方法名定义切点的切面。 3.RegexpMethodPointcutAdvisor:对于按正则表达式匹配方法名进行切点定义的切面,能够经过扩展改实现类进行操做。其内部是经过jdkRegexpMethodPoint构造出正则表达式方法名称切点。 4.StaticMethodMatcherPointcutAdvisor:静态方法匹配切点定义的切面,默认状况下匹配全部的目标类。 5.AspectJExpressionPointcutAdvisor:用于AspectJ切点表达式定义切点的切面。 6.AspectJPointcutAdvisor:用于AspectJ语法定义切点的切切面。
3.IntroductionAdvisor:表明引介切面。引介切面是对应引介加强的特殊的切面,它应用于类层面上,全部切点使用ClassFilter进行定义。
StaticMethodMatcherPointAdvisor表明一个静态方法匹配切面,它经过StaticMethodMatcherPointcut来定义切点,并经过类过滤和方法名来匹配所定义的切点。 例子: Waiter.java
public class Waiter { void greetTo(String name){ System.out.println("Waiter greet to "+name+"..."); } void serveTo(String name){ System.out.println("waiter sering "+name+"..."); } }
Seller.java
public class Seller { public void greetTo(String name){ System.out.println("Waiter greet to "+name+"..."); } }
GreetBeforeAdvice.java(前置加强)
public class GreetBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] objects, Object o) throws Throwable { String clientName = (String)objects[0]; System.out.println("How are you! Mr."+clientName); } }
GreetingAdvisor.java(切面匹配,这里限制只能匹配Waiter的greetTo())
public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor { @Override public boolean matches(Method method, Class<?> targetClass) { return "greetTo".equals(method.getName()); } public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class<?> clazz) { return Waiter.class.isAssignableFrom(clazz); } }; } }
beans.xml
<!--普通静态方法切面匹配--> <bean id="waiterTarget" class="com.flexible.advisormatch.staticmethodadvisormatch.Waiter"></bean> <bean id="sellerTarget" class="com.flexible.advisormatch.staticmethodadvisormatch.Seller"></bean> <bean id="advisormatchGreetingAdvice" class="com.flexible.advisormatch.staticmethodadvisormatch.GreetBeforeAdvice"></bean> <bean id="greetAdvisor" class="com.flexible.advisormatch.staticmethodadvisormatch.GreetingAdvisor" p:advice-ref="advisormatchGreetingAdvice"></bean> <!--这里注入一个前置切面--> <!--经过一个父类定义一个公共的配置信息--> <bean id="parent" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="greetAdvisor" p:proxyTargetClass="true" ></bean> <bean id="advisormatchWaiter" parent="parent" p:target-ref="waiterTarget"></bean> <bean id="advisormatchSeller" parent="parent" p:target-ref="sellerTarget"></bean>
测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("advisormatchWaiter"); Seller seller = (Seller) context.getBean("advisormatchSeller"); waiter.greetTo("zhangsan"); waiter.serveTo("zhangsan"); seller.greetTo("李四");
执行结果:
RegexpMethodPointcutAdvisor是正则表达式方法匹配的切面实现类,改类已是功能齐全的实现类,能够直接拿来使用。
例子: 与上一个例子差异主要再配置文件,beans.xml配置文件的内容以下:
<bean id="waiterTarget2" class="com.flexible.advisormatch.regexpadvisormatch.Waiter"></bean> <bean id="sellerTarget2" class="com.flexible.advisormatch.regexpadvisormatch.Seller"></bean> <bean id="advisormatchGreetingAdvice2" class="com.flexible.advisormatch.regexpadvisormatch.GreetBeforeAdvice"></bean> <bean id="greetAdvisor2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" p:advice-ref="advisormatchGreetingAdvice2"> <property name="patterns"> <list> <value>.*greet.*</value> </list> </property> </bean> <!--经过一个父类定义一个公共的配置信息--> <bean id="parent2" abstract="true" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="greetAdvisor2" p:proxyTargetClass="true" ></bean> <bean id="advisormatchWaiter2" parent="parent2" p:target-ref="waiterTarget2"></bean> <bean id="advisormatchSeller2" parent="parent2" p:target-ref="sellerTarget2"></bean>
DynamicMethodMatcherPointcut抽象类,是Spring用于建立动态切面你的抽象类,改出响雷默认匹配全部的类和方法,所以默认须要扩展该类编写符合要求的动态的切点。 例子: GreetingDynamicPointcut.java
public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut { private static List<String> specialClientList = new ArrayList<>(); static { specialClientList.add("John"); specialClientList.add("Tom"); } // 对类进行静态切点检查 @Override public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class<?> clazz) { System.out.println("调用getClassFilter()对" + clazz.getName() + "作静态检查."); return Waiter.class.isAssignableFrom(clazz); } }; } // 对方法进行静态切点检测 @Override public boolean matches(Method method, Class<?> targetClass) { return super.matches(method, targetClass); } // 对方法进行动态切点检测 @Override public boolean matches(Method method, Class<?> targetClass, Object... args) { System.out.println("调用matches(Method method, Class<?> targetClass, Object... args)" + targetClass.getName() + "." + method.getName()+"作动态检测"); String clientName = (String) args[0]; return specialClientList.contains(clientName); } }
beans.xml
<bean id="waiterTarget3" class="com.flexible.advisormatch.dynamicmatch.Waiter"></bean> <bean id="dynamicAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <property name="pointcut"> <bean class="com.flexible.advisormatch.dynamicmatch.GreetingDynamicPointcut"></bean> </property> <property name="advice"> <bean class="com.flexible.advisormatch.dynamicmatch.GreetBeforeAdvice"></bean> </property> </bean> <bean id="waiter4" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="dynamicAdvisor" p:target-ref="waiterTarget3" p:proxyTargetClass="true"></bean>
测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("waiter4"); waiter.greetTo("John"); waiter.greetTo("John"); waiter.serveTo("zhangsan"); waiter.serveTo("zhangsan");
执行结果:
从执行的结果能够看出,Spring会建立代理织入切面时,对目标类中的全部方法进行了静态切点检查;生成了的植入切面的代理对象后,第一次调用代理类的每个方法都会进行一次静态的检查,若是本次检查就能从候选者列表中将该方法排除,则之后对该方法的调用就再也不执行静态检查;对于静态匹配的方法,后续的调用该方法都会进行动态的检查。
Spring 的流程切面由DefaultPointcutAdvisor和ControlPointcut是实现。流程切点表明由某个方法直接或者简洁的发起调用的其余方法。
例子: WaiterDelegate.java
public class WaiterDelegate { private Waiter waiter; /** * 该方法发起调用的其余方法都织入GreetBeforeAdvice加强, * 要完成该功能就须要使用到流程切面。 * * @param clientName */ public void service(String clientName) { waiter.greetTo("service" + clientName); waiter.serveTo("service" + clientName); } public void setWaiter(Waiter waiter) { this.waiter = waiter; } }
beans.xml
<!--流程切面--> <bean id="controlFlowGreetingAdvice" class="com.flexible.advisormatch.controflowmatch.GreetBeforeAdvice"></bean> <bean id="controlFlowWaiterTarget" class="com.flexible.advisormatch.controflowmatch.Waiter"></bean> <bean id="controlFlowPointcut" class="org.springframework.aop.support.ControlFlowPointcut"> <constructor-arg type="java.lang.Class" value="com.flexible.advisormatch.controflowmatch.WaiterDelegate"></constructor-arg> <constructor-arg type="java.lang.String" value="service"></constructor-arg> </bean> <bean id="controlFlowAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" p:pointcut-ref="controlFlowPointcut" p:advice-ref="controlFlowGreetingAdvice"> </bean> <bean id="controlFlowWaiter1" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="controlFlowAdvisor" p:target-ref="controlFlowWaiterTarget" p:proxyTargetClass="true"> </bean>
测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("controlFlowWaiter1"); WaiterDelegate delegate = new WaiterDelegate(); delegate.setWaiter(waiter); waiter.greetTo("zhangsan"); waiter.serveTo("zhangsan"); delegate.service("zhangsan");
执行结果:
若是一个切点难以描述目标链接点的信息,好比再前面流程切面的例子中,在上面的例子中,若是调用service(String clientName)就会发现该方法调用的两个方法都会织入加强,若是只但愿加强其中一个,那么这个切点就是符合切点。
例子:
GreetingComposablePointcut.java
public class GreetingComposablePointcut { public Pointcut getIntersectionPointcut(){ ComposablePointcut cp = new ComposablePointcut(); Pointcut pt1 = new ControlFlowPointcut(WaiterDelegate.class,"service"); NameMatchMethodPointcut pt2 = new NameMatchMethodPointcut(); pt2.addMethodName("greetTo"); return cp.intersection(pt1).intersection((Pointcut)pt2); } }
beans.xml
<!--复合切点--> <bean id="composableGreetingAdvice" class="com.flexible.advisormatch.composablepointcutmatch.GreetBeforeAdvice"></bean> <bean id="gcp" class="com.flexible.advisormatch.composablepointcutmatch.GreetingComposablePointcut"></bean> <bean id="composableAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor" p:pointcut="#{gcp.intersectionPointcut}" p:advice-ref="composableGreetingAdvice" ></bean> <bean id="composableWaiterTarget" class="com.flexible.advisormatch.composablepointcutmatch.Waiter"></bean> <bean id="composableProxyWaiter" class="org.springframework.aop.framework.ProxyFactoryBean" p:interceptorNames="composableAdvisor" p:target-ref="composableWaiterTarget" p:proxyTargetClass="true"></bean>
测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("composableProxyWaiter"); WaiterDelegate delegate = new WaiterDelegate(); delegate.setWaiter(waiter); waiter.serveTo("zhansagn"); waiter.greetTo("zhangsan"); delegate.service("zhangsgan");
执行结果:
以前的例子都是经过ProxyFactoryBean建立织入切面的代理,每一个须要被代理的Bean都须要配置,这样就会很麻烦,所以Spring提供了自动代理的机制,让容器自动生成代理,把开发从繁琐的配置工做中解放出来。而这些都是Spring内部使用BeanPostProcessor自动完成这项工做。
基于BeanPostProcessor自动代理建立器的实现类有三类: 1.BeanNameAutoProxyCreator:基于Bean配置名规则的自动代理建立器,容许为一组特定的配置名的Bean自动建立代理实例的代理建立器。
例子:
beans.xml
<!--BeanNameAutoProxyCreator自动建立代理类--> <bean id="autoWaiter" class="com.flexible.autoprxycreator.Waiter"></bean> <bean id="autoSeller" class="com.flexible.autoprxycreator.Seller"></bean> <bean id="autoGreetAdvice" class="com.flexible.autoprxycreator.GreetingBeforeAdvice"></bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" //这里能够配置多个须要代理的baean p:beanNames="autoWaiter,autoSeller" p:interceptorNames="autoGreetAdvice" //p:optimize="true"须要配置,实现使用CGLib生成代理 p:optimize="true"></bean>
测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:proxyfactory/beans"); Waiter waiter = (Waiter) context.getBean("autoWaiter"); Seller seller = (Seller) context.getBean("autoSeller"); waiter.greetTo("John"); seller.greetTo("Tom");
执行结果:
com.flexible.autoprxycreator.Waiter.greetTo How are you!Mr.John. waiter greet to John... com.flexible.autoprxycreator.Seller.greetTo How are you!Mr.Tom. seller greet to Tom...
2.DefaultAdvisorAutoProxyCreator:基于Advisor匹配机制的自动代理建立器,他会对容器中的全部的Advisor进行扫描,自动将这些切面应用到匹配的Bean中(为目标Bean建立代理实例)
beans.xml配置
<bean id="autoWaiter2" class="com.flexible.autoprxycreator.defaultautoproxycreator.Waiter"></bean> <bean id="autoSeller2" class="com.flexible.autoprxycreator.defaultautoproxycreator.Seller"></bean> <bean id="autoGreetAdvice2" class="com.flexible.autoprxycreator.defaultautoproxycreator.GreetingBeforeAdvice"></bean> <bean id="regexpMethodPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor" p:advice-ref="autoGreetAdvice2"> <property name="patterns"> <list> <value>.*greet.*</value> </list> </property> </bean> <!--会开启扫描全部的切面 这个地须要配置使用CGLib动态代理--> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" p:proxyTargetClass="true"></bean>
测试代码:
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:autoproxycreator/beans"); Waiter waiter = (Waiter) context.getBean("autoWaiter2"); Seller seller = (Seller) context.getBean("autoSeller2"); waiter.greetTo("John"); seller.greetTo("Tom");
执行结果:
com.flexible.autoprxycreator.defaultautoproxycreator.Waiter.greetTo How are you!Mr.John. waiter greet to John... com.flexible.autoprxycreator.defaultautoproxycreator.Seller.greetTo How are you!Mr.Tom. seller greet to Tom...
3.AnnotationAwareAspectJAutoProxyCreator:基于Bean中AspectJ注解标签的自动代理建立器,为包含AspectJ注解的Bean自动建立代理实例。