Spring----AOP
来源:互联网 发布:oracle删除用户及数据 编辑:程序博客网 时间:2024/05/22 01:30
一、AOP概述
1.1、什么是AOP?
AOP:Aspect Oriented Programing,面向切面编程。
AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
SpringAOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类植入增强代码。
1.2、AOP底层原理
AOP的顶层实现原理就是代理机制。
1.3、Spring的AOP代理(一窥)
JDK动态代理:对实现了接口的类生成代理。
CGLib代理机制:对类生成代理。
1.4、AOP术语
- Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在Spring中,这些点指的是方法,因为Spring只支持方法类型的连接点。
- Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
- Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情。通知分为前置通知、后置通知、异常通知、最终通知、环绕通知。
- Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下,Introduction可以在运行期间为类动态地添加一些方法或Field。
- Target(目标对象):代理的目标对象。
- Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
- Proxy(代理):一个类被AOP织入增强后就产生一个结果代理类。
- Aspect(切面):是切入点和通知(引介)的结合。
1.5、AOP底层实现(二探)
JDK动态代理机制
CGLib代理机制
二、Spring中的AOP
2.1、Spring的传统AOP
Spring中的通知:
- 前置通知(org.springframework.aop.MethodBeforeAdvice):在目标方法执行前实施增强。
- 后置通知(org.springframework.aop.AfterReturningAdvice):在目标方法执行后实施增强。
- 环绕通知(org.aopalliance.intercept.MethodInterceptor):在目标方法执行前后实施增强。
- 异常抛出通知(org.springframework.aop.ThrowsAdvice):在方法抛出异常后实施增强。
- 引介通知(org.springframework.aop.IntroductionInterceptor):在目标类中添加一些新的方法和属性。
Spring中的切面类型:
- Advisor:Spring中的传统切面,一个切点和一个通知的组合。
- Aspect:多个切点和多个通知的组合。
Advisor:代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截(不带切点的切面,对所有方法进行拦截)。
PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类的某些方法(带有切点的切面,对指定方法进行拦截)。
三、Spring的AOP开发
3.1、不带切点的切面
第一步:导入相应的jar包
- spring-aop-3.2.0.RELEASE.jar
- com.springsource.org.aopalliance-1.0.0.jar
第二步:编写被代理的对象
BookDao接口:
public interface BookDao { public void add(); public void delete(); public void update(); public void serach();}
BookDaoImpl实现类
第三步:编写增强的代码
import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;public class MyBeforeAdvice implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("进行前置增强!"); }}
第四步:生成代理
Spring通过配置生产代理。
Spring生产代理基于ProxyFactoryBean类,底层自动选择使用JDK的动态代理还是CGlib的代理。
ProxyFactoryBean类属性:
target:代理的目标对象。
proxyInterfaces:代理要实现的接口。
如果多个接口可以使用以下格式赋值:
<list>
<value></value>
<value></value>
<value></value>
………
</list>
proxyTargetClass:是否对类代理而不是接口,设置为true时,使用CGlib代理。
interceptorNames:需要织入目标的Advice。
singleton:返回代理是否为单例,默认为单例。
optimize:当设置为true时,强制使用CGlib。
在applicationContent.xml中进行配置:
<!-- 定义目标对象 --> <bean id="bookDao" class="cn.xpu.hcp.impl.BookDaoImpl"></bean> <!-- 定义增强 --> <bean id="beforeAdvice" class="cn.xpu.hcp.advice.MyBeforeAdvice"></bean> <!-- Spring支持配置生成代理 --> <bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 设置目标对象 --> <property name="target" ref="bookDao"/> <!-- 设置实现的接口,value中写接口的全路径 --> <property name="proxyInterfaces" value="cn.xpu.hcp.dao.BookDao"/> <!-- 设置增强 ,使用value而不是ref--> <property name="interceptorNames" value="beforeAdvice"></property> </bean>
第五步:测试
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class AopTest { @Autowired @Qualifier("bookDaoProxy")//注入代理对象 private BookDao bookDao; @Test public void test() { bookDao.add(); bookDao.delete(); bookDao.update(); bookDao.serach(); }}
测试结果:
3.2、带切点的切面
使用不带切点的切面对所有方法进行了增强,当我们只对特定方法实现增强时这就不适用了。我们选择带切点的切面。
PointcutAdvisor接口:
DefaultPointcutAdvisor:最常用的切面类型,他可以通过任意Pointcut和Advice组合定义切面。
RefexpMethodPointcutAdvisor:构造正则表达式切点切面。
第一步:创建被代理对象
我使用和上面一样的
第二步:编写增强的类
我选择环绕增强。
import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;public class MyAroundAdvice implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("环绕前增强。。。"); Object result = invocation.proceed();//执行目标对象的方法 System.out.println("环绕后增强。。。"); return result; }}
第三步:使用配置生成代理
<!-- 定义目标对象 --> <bean id="bookDao" class="cn.xpu.hcp.impl.BookDaoImpl"></bean> <!-- 定义增强 --> <bean id="aroundAdvice" class="cn.xpu.hcp.advice.MyAroundAdvice"></bean> <!-- 定义切点、切面 --> <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <!-- 使用正则表达式,规定哪些方法执行增强 --> <!-- .表示任意字符;*表示任意个 --> <!--<property name="pattern" value=".*"/>--><!-- .* 表示任意方法,和不带切点切面一样了 --> <!--<property name="pattern" value="cn\.xpu\.hcp\.impl\.BookDaoImpl\.add.*"/>--><!-- cn.xpu.hcp.impl.BookDaoImpl 中add开头的方法 --> <property name="pattern" value=".*add.*"/> <!-- 具体应用至哪个增强 --> <property name="advice" ref="aroundAdvice"/> </bean> <!-- 定义生成代理对象 --> <bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!-- 设置目标对象 --> <property name="target" ref="bookDao"/> <!-- 针对类的代理,使用CGlib --> <property name="proxyTargetClass" value="true"/> <!-- 设置增强 --> <property name="interceptorNames" value="myPointcutAdvisor"/> </bean>
第四步:编写测试类
与上面一样
测试结果:
只对add方法进行了增强。
3.3、自动代理
在前面的代理中每个代理都要通过ProxyFactoryBean织入切面代理,在时间开发中非常多的Bean每个都配置ProxyFactoryBean开发量可想而知非常大。
自动创建代理其实就是基于后处理Bean。在Bean创建的过程中完成的增强,生成的Bean就是代理。
BeanNameAutoProxyCreator根据Bean名称创建代理。
DeafultAdvisorAutoProxyCreator根据Advisor本身包含信息创建代理。
3.3.1、BeanNameAutoProxyCreator:按名称生成代理
配置applicationContext.xml:
<!-- 定义目标对象 --> <bean id="bookDao" class="cn.xpu.hcp.impl.BookDaoImpl"/> <bean id="orderDao" class="cn.xpu.hcp.dao.OrderDao"/> <!-- 定义增强 --> <bean id="beforeAdvice" class="cn.xpu.hcp.advice.MyBeforeAdvice"/> <bean id="aroundAdvice" class="cn.xpu.hcp.advice.MyAroundAdvice"/> <!-- 自动代理:按名称的代理,基于后处理Bean,后处理Bean不需要配置ID --> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames" value="*Dao"/> <property name="interceptorNames" value="aroundAdvice"/> </bean>
根据名称,只对Dao进行增强,具体使用哪个增强可以很方便的修改。
测试:
@Autowired @Qualifier("orderDao") private OrderDao orderDao; @Autowired @Qualifier("bookDao") private BookDao bookDao; @Test public void test() { bookDao.add(); bookDao.delete(); orderDao.add(); orderDao.delete(); }
结果:
3.3.2、DefaultAdvisorAutoProxyCreator:根据切面中定义的信息生成代理
配置applicationContext.xml:
<!-- 定义目标对象 --> <bean id="bookDao" class="cn.xpu.hcp.impl.BookDaoImpl"/> <bean id="orderDao" class="cn.xpu.hcp.dao.OrderDao"/> <!-- 定义增强 --> <bean id="beforeAdvice" class="cn.xpu.hcp.advice.MyBeforeAdvice"/> <bean id="aroundAdvice" class="cn.xpu.hcp.advice.MyAroundAdvice"/> <!-- 定义带切点的切面 --> <bean id="myPointcutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <property name="pattern" value=".*add.*"/> <property name="advice" ref="beforeAdvice"/> </bean> <!-- 自动代理 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"> </bean>
测试代码相同。
测试结果:
ProxyFactoryBean与自动代理的区别?
答:ProxyFactoryBean:先有被代理对象,将被代理对象传入到代理类中生成代理。
自动代理基于后处理Bean。在Bean的生成过程中就产生了代理对象,把代理对象返回。生成Bean已经是代理对象。
- AOP、Spring的AOP
- AOP--Spring AOP
- Spring AOP 嵌套AOP
- spring AOP
- Spring AOP
- Spring AOP
- spring aop
- Spring AOP
- spring AOP
- spring aop
- Spring aop
- Spring-AOP
- Spring AOP
- spring aop
- spring aop
- Spring AOP
- Spring AOP
- Spring Aop
- zabbix-邮件告警配置
- 【每周一本书】之《白话大数据与机器学习》
- Mybatis pagehelper分页插件使用
- 使用maven profile实现多环境可移植构建
- 2017金猿榜之年度大数据企业榜即将发布!
- Spring----AOP
- C++ 学习系列(二)#include解析
- Android适配——drawable和values的加载规则
- atitit 部门日常工作流程体系 日常日程表 日常工作内容列表清单.docx
- package.json配置说明
- 如何修改sublime3注释的颜色
- SQL Server
- HDU 5543 Pick The Sticks【0-1背包】
- Mysql备份与还原(二)