1、前置增强
继承与MethodBeforeAdvice,并实现before方法,用于在目标类方法前执行。
在配置文件中:
<bean id="a" class="继承于MethodBeforeAdvice接口的类"/>
<bean id="b" class="原始类"/>
<bean id="c" class="org.springframework.aop.framework.ProxyFactoryBean">
p:proxyInterfaces="代理的接口,即原始类的接口"
p:interceptorNames="a"//指定使用的增强
p:target-ref="b"//被代理的类
p:其它属性
</bean>
2、后置增强
继承于AfterReturningAdvice,并实现afterReturning方法,用于在目标类方法调用后执行。
3、环绕增强
继承于MethodInterceptor,并实现invoke方法,综合了前两者。
4、异常抛出增强
最适合用在事务中,异常时回滚
继承于ThrowsAdvice,必须实现方法afterThrowing(...)
5、引介增强
类 extends DelegatingIntroductionInterceptor implements 新增的接口,并实现接口中的方法。它是一种类级别的增强。
前面介绍的增强用于织入到方法的前面,后面等信息,而切点进一步描述织入到哪些类的哪些方法上
6、静态普通方法名匹配切面
默认匹配所有类及方法,所以一般情况下需要自己改写。类extends StaticMethodMatcherPointcutAdvisor,重写matches(Method method, Class clazz)方法,可以匹配指定的方法名。通过改写getClassFilter方法,可以使得匹配规则限定某些类。
7、静态正则表达式方法匹配切面
略
8、动态切面
类 extends DynamicMethodMatcherPointcut,重写matches(Method method, Class clazz, Object[] args)方法。再在spring中进行动态切面的配置就装配好了。
9、流程切面
由某一个方法发起对其它方法的调用都织入增强,就可以使用流程切面来完成。
10、复合切点切面
如果希望由某一个方法发起对特定一个方法的增强时
11、引介切面
略
12、自动创建代理
上面的切面配置比较麻烦,spring提供了简单的配置方法(1)基于Bean配置名规则的自动代理创建器,BeanNameAutoProxyCreator
(2)基于Advisor匹配机制的自动代理创建器,DefaultAdvisorAutoProxyCreator
(3)基于AspjectJ注解标签的自动代理创建器,AnnotationAwareAspectJAutoProxyCreator
下面介绍更为简单的配置AOP的方法(基于@AspectJ和schema)
使用@AspectJ需要JDK5.0以上,spring的asm模块,aspectj.weaver,aspectj.tools类包
13、基于AspectJ的简单例子
@Aspect
public class PreGreetingAspect{
@Before("execution(* greetTo(..))")
public void beforeGreeting(){
System.out.println("How are you");
}
}
这样就表示执行任何greetTo方法时织入前置增强,然后进行spring的配置:
<beans>
<aop:aspectj-autoproxy proxy-target-class="true"/>//true表示用CGLib动态代理技术
<bean id="waiter" class="com.xxx.NaiveWaiter"/>//目标类
<bean class="PreGreetingAspect的全限定名"/>
</beans>
(1)execution:执行目标类方法
execution(public * *To(..)):以To为后缀的public方法
execution(* com.xxx.Waiter.*(..)):匹配Waiter接口的所有方法
execution(* com.xxx.Waiter+.*(..)):匹配Waiter接口及其实现类中的所有方法
execution(* com.xxx.*(..)):xxx包下的所有类的所有方法
execution(* com.xxx..*(..)):xxx包,子孙包下的所有类的所有方法
execution(* com..*.*Dao.find*(..)):前缀为com的任何包下后缀为Dao的方法,且方法前缀为find
execution(* joke(String, ..)):*表示任何类型,..表示任意类型且参数个数不限
即.* 表示包下所有类,..*表示包及子孙包下所有类
(2)@annotation:所有指定注解的目标类方法
(3)args:方法接受一个类名
args(com.xxx.Waiter):匹配运行时入参时Waiter类型(包含子类)的方法,等价于args(com.xxx.Waiter+),也等价于execution(* *(com.xxx.Waiter+))
(4)@args:方法接受一个类名且必须接受一个注解类的类名
(5)within:最小粒度是类
(6)target
(7)@within
(8)@target
(9)this
。。。
且以上方法的入参支持的通配符不同
除@AspectJ注解的方式之外,其它还有<aop:advisor>方式(如引用第三方包中的增强和切点),<aop:aspect>方式等
14、逻辑运算符与:&&的转义符(&&)或者 使用and
或:|| 或者 or
非:! 或者 not,当not位于表达式开头时,开头必须加一个空格
15、增强类型
@Before
@AfterReturning
@Around
@AfterThrowing
@After
@DeclareParents
16、命名切点
public class TestNamePointcut{
@Pointcut("within(com.xxx.*)")
private void inPackage(){} //private表示只能在本类中引用,inPackage()是切点名称
@Pointcut("execution(* greetTo(..))")
protected void greetTo(){}
@Pointcut("inPackage() and greetTo()") //此处引用inPackage()和greetTo()的命名切点,并设为public
public void inPkgGreetTo(){}
}
public class TestAspect{
@Before("TestNamePointcut.inPkgGreetTo()")//引用其它类中的public切点
public void pkgGreetTo(){
//todo ...
}
}
17、增强织入的顺序
略
18、以上args(),this()等都是通过指定类名来匹配的,还可以通过匹配参数名
@Before(args(name, num, ..))
public void func(int num, String name) //这里就通过name和num参数名称相当于args(String, int)
19、AOP代理中的proxy-target-class 参数
如果你希望在不改变代码的情况 下代理目标对象的所有方法,而不只是实现自接口的方法(强制使用CGLIB代理),见http://www.xuebuyuan.com/993356.html
20、JDK&CGLib代理
JDK基于接口的动态代理要求方法必须是public的,且static由于是类级别的,public static接口也是不行的,public final则可以
CGLib通过扩展被增强类,动态创建其子类的方式实现动态代理,所以private,static,final修饰的方法都不行