AOP应用:日志、安全、声明式事务、缓存等
Spring的aop基于动态代理,只能实现方法拦截,要实现字段拦截和构造器拦截,可使用AspectJ或者JBoss。
以下是几个需要掌握的概念:
通知:通知定义了切面是什么及什么时候应用。分为前置后置等等。
连接点:应用执行过程中能够插入切面的一个点。
切点:定义了切面在何处应用。
切面:通知+切点
引入:允许我们向现有类添加方法或属性。
织入:把切面应用到目标对象并创建新的代理对象的过程。
个人理解:比如一个工厂会产生垃圾,而工厂只负责生产,垃圾希望由切面执行,连接点是可能(但不一定)产生垃圾,并希望切面作用的点,而切点是产生了垃圾并需要切面作用的点,通知即我希望什么时候切面去处理切点处的垃圾以及如何处理,织入即把切面覆盖在目标对象的切点方法上面,一旦调用目标对象的这些符合切点的方法,目标对象的代理对象将会拦截调用,然后执行通知方法,再转发调用给目标对象。引入是通过引入新的接口为对象添加方法等。
编译期织入:AspectJ
类加载期织入:AspectJ 5支持
运行期织入:Spring aop
Spring AOP的AspectJ切点,Spring仅支持AspectJ切点指示器的一个子集,其中只有execution()指示器是执行匹配,其他都是用来限制匹配的。
在一个类上使用@Aspect注解即可使该类成为一个切面(AspectJ 5),切面包含通知及切点,例如:
@Aspect // 这个注解使此类成为切面
public class a_Aspect {
// 切点
@Pointcut("execution(* chapter4.Domain.*(..))")
public void perform() {
}
// 通知
@Before("perform()")
public void before() {
System.out.println("前置通知");
}
@After("perform()")
public void after() {
System.out.println("后置通知");
}
@Around("perform()")
public void around(ProceedingJoinPoint pjp) {
try {
before();
pjp.proceed();
after();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这里重点是环绕通知,如果要在前置通知和后置通知间共享信息,那么得有一个新的成员变量传递信息,环绕通知在内部实现了信息共享。
要使切面类发挥作用,还需要配置类的一个注解,如下:
@Configuration
@ComponentScan
@EnableAspectJAutoProxy//启动自动代理,切面类才能发挥作用
//对应xml为<aop:aspectj-autoproxy>
public class Config {
@Bean
public a_Aspect getAspect() {
return new a_Aspect();
}
}
想为目标bean添加方法,则要新建一个接口NewMethod和其实现类DefaultNewMethod,重点是这一步:
//新建一个切面类,为目标添加方法
@Aspect
public class NewMethod_Aspect {
//value:哪种类型的bean要引入该接口,加号表示此类的子类也行
//defaultImpl:使用该接口的哪个实现类
@DeclareParents(value="chapter4.Domain+",defaultImpl=DefaultNewMethod.class )
public NewMethod nm;
}
对应xml配置为:
<!-- 匹配接口interfaceA的bean会在父类中实现interfaceB接口-->
<aop:declare-parents types-matching="interfaceA+" implement-interface="interfaceB" default-impl="interfaceB_Imp"/>
<!-- 也可以这样,但是interfaceB_Imp这个bean要自己装配-->
<aop:declare-parents types-matching="interfaceA+" implement-interface="interfaceB"delegate-ref="interfaceB_Imp"/>
</aop:aspect>
测试类里:为Domain类添加一个新方法g()
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Config.class)
public class TestDemo {
@Autowired
private Domain d;
@Test
public void test() {
d.fun();
NewMethod nm = (NewMethod) d;
nm.g();
}
}
如果你需要声明切面,但是又不能为通知类添加注解的时候,那么就必须转向XML配置了。
Spring的AOP功能不及AspectJ,所以我们有必要使用AJDT插件开发,插件网站:http://www.eclipse.org/ajdt/downloads/
语法及具体使用我也不知道了。。。
最后,如果通知方法有参数,我们希望传入切点方法的参数也传给通知方法:
<aop:pointcut expression="execution(* chapter4.*(int))and args(count)" id="pc"/>