SpringAOP总结

spring中AOP功能的实现有以下俩种情况:
1.如果目标对象实现了接口,默认情况下会采用JDK的动态代理来实现AOP功能
2.如果目标对象没有实现接口,spring会使用CGLIB的库来实现代理类实现AOP功能
注:spring会在JDK动态代理和CGLIB之间自动选择

AOP的一些基本概念:
AOP 面向切面编程
aspect 切面/切面类 即附加功能类
joinPoint 连接点,目标类中每一个方法都是一个连接点
pointCut 切入点,一切连接点的集合
advice 通知/拦截器,用来控制切面类将来的位置(切入点的前面、后面或抛异常时)
adivsor 增强器,用来筛选目标类中那些方法是我们的连接点(需要被拦截)
target 目标对象
proxy 代理对象
wave 织入

advice(通知类型):

 Before advice              
 前置通知,连接点执行前执行
 After returning advice    
 返回后通知(在连接点(目标方法)正常完成后执行(没有异常))
 After throwing advice    
 在连接点抛出异常退出时执行
 After (finally) advice
 在连接点退出时执行(不管连接点是否有异常都会执行)
 Around Advice
 环绕通知,包围一个连接点的通知,例如事务的处理,就需要这样的通知,因为事务需要在方法前开启,在方法后提交,以及方法抛出异常时候回滚(相当于before、after通知一起用),这种方法相对与同时写多个通知线程安全

 当AroundAdvice与before、after通知一起用时,AroundAdvice最先执行,执行完方法后执行AroundAdvice,最后执行after
 执行顺序相当于
try {
    try {
        aroundAdvice();
        beforeAdvice();
        pointcut();
    } finally {
        afterAdvice();
    }
    aroundAdvice();
    afterReturningAdvice();
    return;
} catch (Exception e) {
    afterThrowingAdvice(e);
    return;
}  

每一个通知都有对应的接口:
MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice、MethodInterceptor

有目标类(有切入点)(需要实现接口)、切面类

Before advice和After returning advice
新建一个类(通知类),实现通知对应接口,有切面类属性,实现对应接口内的抽象方法(方法内部不用手动调用对应切入点,Spring会自动调用)

AroundAdvice
新建一个类(通知类),实现通知对应接口,有切面类属性,实现对应接口内的抽象方法(参数为:MethodInvocation mi):
在要执行连接点时执行
Object returnValue = mi.proceed();
最后将returnValue返回即可

After throwing advice
新建一个类,实现通知对应接口 (ThrowsAdvice 是一个空接口,起标识作用),有切面类属性,增加方法afterThrowing()并实现,
这个方法可以是一参(Exception e),也可以是四参(Method method, Object[] args, Object target,Exception e)

配置xml文件:
配置目标类、切面类、通知类
然后配置代理对象:

<!-- 配置代理对象 -->
<!-- 这里使用的是spring的一个代理对象工厂类产生的 -->
<bean name="proxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
     <!-- 注入目标对象 -->
     <property name="target" ref="target"></property>
    
     <!-- 注入目标对象所实现的接口 可以有多个接口 -->
     <property name="proxyInterfaces">
          <list>
          <value>com.briup.aop.service.IAccountService</value>
          </list>
     </property>
    
     <!-- 注入advice  可以有多个 -->
     <property name="interceptorNames">
          <list>
               <value>beforeAdvice</value>
               <value>afterAdvice</value>
               <value>aroundAdvice</value>
               <value>throwAdvice</value>
          </list>
     </property>
</bean>

advisor 增强器
作用:筛选目标对象中要代理的方法,之前的advice是把目标对象中的所有方法全部都进行代理
spring中已经给我们提供了实现类RegexpMethodPointcutAdvisor,在xml中直接配使用就可以了
有目标类(需要实现接口)、切面类、通知器类
xml中配置目标类、切面类、通知器类
配置增强器:

<bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     <!-- 注入advice 表示增强器要在哪一个advice起作用-->
     <property name="advice" ref="beforeAdvice"></property>
     <!-- 注入需要被拦截的目标对象中的方法(连接点) -->
     <property name="patterns">
          <list>
               <value>.*bankAction</value>
          </list>
     </property>
</bean>

配置代理对象:

<!-- 这里使用的是spring的一个代理对象工厂类产生的 -->
<bean name="proxy"
class="org.springframework.aop.framework.ProxyFactoryBean">
     <!-- 注入目标对象 -->
     <property name="target" ref="target"></property>
    
     <!-- 注入目标对象所实现的接口 可以有多个接口 -->
     <property name="proxyInterfaces">
          <list>
               <value>com.briup.aop.service.IAccountService</value>
          </list>
     </property>
    
     <!-- 注入advice/advisor  可以有多个 -->
     <property name="interceptorNames">
          <list>
               <value>advisor</value>
          </list>
     </property>
</bean>

注意:另外spring还提供了一个增强器:NameMatchMethodPointcutAdvisor
这个增强器的配置方式和上面的类似,不同之处在于可以利用setMappedNames方法直接注明要处理的方法名字

AutoProxy
自动代理:DefaultAdvisorAutoProxyCreator类的使用

使用原因:在配置文件中我们往往需要给很多个目标对象设置代理对象,那么就需要每个目标对象的代理对象都需要配置一套类似的标签,通过自动代理可以用很少的配置为xml文件中的目标对象自动的生成对应的代理对象

配置:
在xml中配置目标类、切面类、通知器、增强器
配置代理对象(自动代理方式):

<!-- 注意:这不是一个工厂类,所以不能用过proxy来拿代理对象 -->
<bean name="proxy"
      class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
</bean>

使用自动代理的时候需要注意的方面:
1.当前的配置里面一定要配置有advisor
2.不需要向自动代理类中注入任何信息
3.不管目标对象是否实现了一个或多接口,自动代理的方式都能够为它产生代理对象(CGLib的方式).
4.从spring容器中拿代理对象的时候,需要通过目标对象的名字来拿。
5.spring如何确定配置文件中哪个bean是作为目标对象:
通过advisor中筛选的方法,如果这个bean中含有advisor中所配置的方法,则这个bean将来称为我们的目标对象进行代理

AutoProxyByName
通过名字进行自动代理:BeanNameAutoProxyCreator类的使用

通过名字进行自动代理可以筛选出给哪些对象进行自动代理

配置:
在xml中配置目标类、切面类、通知器、增强器
配置代理对象(自动代理方式):

<bean name="proxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
     <!-- 注入需要被代理的对象名字 -->
     <property name="beanNames">
          <list>
               <value>target</value>
               <value>target2</value>
               <value>dao</value>
               <value>service*</value>
          </list>
     </property>
    
     <!-- 注入advice或者advisor -->
     <property name="interceptorNames">
          <list>
               <value>advisor</value>
          </list>
     </property>
</bean>

使用byName自动代理的时候需要注意的方面:
1.当前的配置里面"有没有"advisor的配置"都没关系"
2.需要向自动代理类中注入被代理目标对象的名字已经advice或者advisor
3.不管目标对象是否实现了一个或多接口,自动代理的方式都能够为它产生代理对象.
4.从spring容器中拿代理对象的时候,需要通过目标对象的名字来拿。

aop:config标签

 使用aop的专用标签来完成相关的配置

 主要使用AspectJ的expression的操作:
 execution(modifiers-pattern ret-type-pattern declaring-type-pattern name-pattern(param-pattern) throws-pattern)除了返回类型模式,名字模式和参数模式以外,所有的部分都是可选的。

使用前需要在xml的beans标签中加入新的schame文件,并在eclipse中进行关联配置

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> 

使用方法:
在xml中配置目标类、切面类、通知器、增强器
配置aop代理:

<aop:config>
     <!-- 定义一个切入点 并给切入点起名为myPointCut -->
     <!-- 切入点是一组连接点的集合 -->
     <aop:pointcut expression="execution(public * com.briup.aop.service.*.*(..))" id="myPointCut"/>
     <!-- 定义哪一个advice在哪一个切入点上面起作用 -->
     <aop:advisor advice-ref="beforeAdvice" pointcut-ref="myPointCut" />
</aop:config>

使用规则:
最常用的返回类型模式是 *,表示匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 * 通配符作为所有或者部分命名模式。

参数模式稍微有点复杂:
() 表示匹配一个不接受任何参数的方法
(…) 表示匹配一个接受任意数量参数的方法(零或者更多)。
() 表示匹配一个接受一个任何类型的参数的方法。
(
,String) 表示匹配一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型

常用切入点表达式例子:
1)任意包下的任意类中的公共方法的执行:
execution(public * (…))
2)任何一个以“set”开始的方法的执行:
execution(
set*(…))
3)AccountService 接口的任意方法的执行:
execution(* com.briup.service.AccountService.(…))
4)定义在service包里的任意方法的执行:
execution(
com.briup.service..(…))
5)定义在service包或者子包里的任意方法的执行:
execution(* com.briup.service..(…))
6)execution(public * com.briup.aop.service..(…))
表达式中从左到右的号:
第一个
表示方法的返回类型不限。
第二个* 表示包中的任意一个类
第三个* 表示类中的任意一个方法

注意:<aop:config proxy-target-class=“true”> 如果这样配置则是强制使用CGLIB方式进行代理

简化配置通知器:
写一个切面类,切面类中定义多个方法(beforeAdvice,afterAdvice…),并在xml文件的aop标签中进行配置

新建一个类(切面类)并新建方法实现对应通知:

before advice、after advice、
after Returning advice 对应方法参数为JoinPoint p 例:

public void beforeTest(JoinPoint p){
     System.out.println(p.getSignature().getName()+" before...");
}

After throwing advice
对应方法参数为JoinPoint p,Exception ex 例:

public void throwingTest(JoinPoint p,Exception ex){
     System.out.println(p.getSignature().getName()+" is throwing..."+ex.getMessage())    
}

around Advice
对应方法参数为ProceedingJoinPoint pjp
使用方法:

public Object aroundTest(ProceedingJoinPoint pjp)throws Throwable{
     //JoinPoint对象不能调用连接点所表示的方法
     //ProceedingJoinPoint能调用连接点所表示的方法 pjp.proceed()
     System.out.println(pjp.getSignature().getName()+" is start..");
     //调用到连接点方法
     Object obj = pjp.proceed();
     System.out.println(pjp.getSignature().getName()+" is end..");
     return obj;
}

xml中配置目标类、切面类(起名为handler)
配置aop代理:

<aop:config>
     <!-- 定义切入点名为myPointCut -->
     <aop:pointcut expression="execution(public * com.briup.aop.service.*.*(..))" id="myPointCut"/>
    
     <!-- 定义切面类 以及需要使用的advice -->
     <aop:aspect id="aspect" ref="handler">
          <!-- 表示beforeAdvice会把切面类handler中的beforeTest方法织入到名字叫myPointCut的切入点上面 -->
          <aop:before method="beforeTest" pointcut-ref="myPointCut"/>
          <!-- after表示不管方法是否正常结束都会起作用 -->
          <aop:after method="afterTest" pointcut-ref="myPointCut"/>
          <!-- after-returning表示方法正常结束才会起作用(抛异常时候不起作用) -->
          <aop:after-returning method="afterReturningTest" pointcut-ref="myPointCut"/>
          <aop:around method="aroundTest" pointcut-ref="myPointCut"/>
          <!-- throwing="ex"表示throwingTest方法中接收异常对象的名字一定要是ex -->
          <aop:after-throwing method="throwingTest" pointcut-ref="myPointCut" throwing="ex"/>
     </aop:aspect>
</aop:config>

注意:<aop:config proxy-target-class=“true”> 如果这样配置则是强制使用CGLIB方式进行代理

使用注解配置AOP:
其实就是在上面的类XmlHandler中加入上注解,然后去掉xml中的aop标签配置
在类名上方注 @Aspect 表示这个类是一个切面类

在这个类里新建一个方法,这个方法本身不需要有什么作用,意义就是给 @Pointcut注解一个书写的地方,因为注解只能写在方法、属性、类的上面,并且方法名作为切入点的名字

@Pointcut("execution(public * com.briup.aop.service..*.*(..))")
public void myPointCut(){}

在每个通知方法上面写对应的注解:
@Before、 @After、 @AfterReturning、 @Around、AfterThrowing

xml中配置:

<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.briup.aop"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值