提前说明一下,实际开发中一般不会使用传统aop进行开发,而是会使用aspectJ。但是这个是aspectJ的基础,有助于理解。
1. 通知类型
- AOP联盟为通知advice定义了org.aopalliance.aop.Interface.Advice,即接口规范
- Spring按照通知Advice在目标类方法的连接点位置,可以分为5类:
- 前置通知 org.springframework.aop.MethodBeforeAdvice
- 在目标方法执行前实施增强
- 后置通知 org.springframework.aop.AfterReturningAdvice
- 在目标方法执行后实施增强
- 环绕通知 org.aopalliance.intercept.MethodInterceptor
- 在目标方法执行前后实施增强
- 异常抛出通知 org.springframework.aop.ThrowsAdvice
- 在方法抛出异常后实施增强
- 前置通知 org.springframework.aop.MethodBeforeAdvice
2. 切面类型
- Advisor:代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截
- PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类哪些方法
3. 具体使用方式
3.1 准备工作
- pom.xml中引入传统aop依赖包
aopalliance aopalliance 1.0 org.springframework spring-aop 4.3.18.RELEASE
- 创建接口类
package com.aop.traditional;public interface StudentDao { public void find(); public void save(); public void update(); public void delete();}
- 创建接口实现类
package com.aop.traditional;public class StudentDaoImpl implements StudentDao { public void find() { System.out.println("查询"); } public void save() { System.out.println("保存"); } public void update() { System.out.println("更新"); } public void delete() { System.out.println("删除"); }}
- 创建配置文件
3.2 普通切面增强整个目标类
我们要告诉spring,我们要在哪对谁进行增强啥。
- 创建前置通知类
package com.aop.traditional;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;public class BeforeAdvice implements MethodBeforeAdvice { public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("前置通知========="); }}
- 配置文件注册bean
- spring aop产生代理对象,借助ProxyFactoryBean产生代理对象。重要的属性如下:
- 调用
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:application-context-aop.xml")public class SpringDemo { @Resource(name="studentDaoProxy") private StudentDao studentDao; @Test public void demo1() { studentDao.save(); studentDao.find(); studentDao.update(); studentDao.delete(); }}
3.3 PointcutAdvisor 带切点的切面增强类方法
- 使用普通advice作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用带有切点的切面。
- 常用的PointcutAdvisor实现类
- DefaultPointcutAdvisor
- RegexpMethodPointcut 正则表达式切点,推荐用这个
3.2中的栗子使用RegexpMethodPointcut 实现,只需要修改xml中的配置项即可,有一次显示了aop的灵活性。
对delete和save方法进行前置通知增强。
3.4 自动创建代理
- 前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量都巨大。
- 解决方案:自动创建代理
- BeanNameAutoProxyCreator 根据Bean名称创建代理,比如:所有后边带dao的bean都代理
- DefaultAdvisorAutoProxyCreator 根据advisor中的信息创建代理
- AnnotationAwareAspectJAutoProxyCreator 基于Bean中的AspectJ注解进行自动代理,这个在后边还会讲,此处略过。
3.4.1 BeanNameAutoProxyCreator 举例
对所有以dao结尾的bean的所有方法使用代理,注意该方式又只能是所有方法!!!!
细心的话,可以看到,BeanNameAutoProxyCreator是没有设置id的,说明我们不会主动注入。这个其实是在bean的postProcessAfterInitialization的声明周期阶段执行的,即是在bean初始化阶段就将增强注入进去了。这个跟其他的方式不同,其他的是先创建bean,在对bean进行代理。
3.4.2 DefaultAdvisorAutoProxyCreator 举例
这个DefaultAdvisorAutoProxyCreator将扫描上下文,寻找所有的Advistor(一个Advisor是一个切入点和一个通知的组成),将这些Advisor应用到所有符合切入点的Bean中 。