Spring(AOP)

AOP详解

  • 基本定义
  1. 通知
    是指拦截到JointPoint之后需要做的事情
    spring的五种通知类型
    1) Before通知,即在方法调用之前调用通知
    2) After通知,即方法完成之后调用通知,无论方法执行成功与否
    3) After-returning通知,即在方法执行成功之后调用通知
    4) After-throwing通知,即在方法抛出异常后调用通知
    5) Around通知,即环绕通知
  2. 连接点(Joinpoint)
    是指哪些方法可以被拦截
  3. 切入点(Pointcut)
    要对哪些方法进行拦截
  4. 切面(Aspect)
    切面是通知和切入点的集合。通知和切入点共同定义了切面的全部功能–它是什么,在何时何处完成其功能
  5. 引介(Introduction)
    引入允许我们向现有的类中添加方法或属性
  6. 目标对象(Target)
    代理的目标对象,需要被增强的对象
  7. 织入(Weaving)
    是指把增强应用到目标对象来创建新的代理对象的过程
  8. 代理(Proxy)
    一个类被AOP织入增强后,就产生一个结果代理类
  • 前置通知
  1. 接口
package com.jd.wang;
public interface ISomeService {
        public void doFirst();
}
  1. 实现
package com.jd.wang;
public class SomeService implements ISomeService {
        public void doFirst() {
                // TODO Auto-generated method stub
                System.out.println("doFirst");
        }
}
  1. 通知
package com.jd.wang;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class MyMethodBeforeAdvice implements MethodBeforeAdvice{
        @Override
        public void before(Method method, Object[] args, Object target)
                        throws Throwable {
                // TODO Auto-generated method stub
                System.out.print("执行前置通知方法");   
        }
}
  1. 注册

     <?xml version="1.0" encoding="UTF-8"?>
     <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
             <bean id="someService" class="com.jd.wang.SomeService"></bean>
             <bean id="myAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean>
             <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                     <property name="target" ref="someService"></property>
                     <property name="interceptorNames" value="myAdvice"></property>
             </bean>
     </beans>
    

注:此处使用了代理工厂bean(proxyfactorybean)

  • 后置通知

      package com.jd.wang;
      import java.lang.reflect.Method;
      import org.springframework.aop.AfterReturningAdvice;
      public class MyAfterReturningAdvice implements AfterReturningAdvice {
              @Override
              public void afterReturning(Object returnValue, Method method,
                              Object[] args, Object target) throws Throwable {
                      // TODO Auto-generated method stub
                      System.out.println("执行后置通知");
              }
      }
    
  • 环绕通知

      package com.jd.wang;
      import org.aopalliance.intercept.MethodInterceptor;
      import org.aopalliance.intercept.MethodInvocation;
      public class MyMethodInterceptor implements MethodInterceptor {
              @Override
              public Object invoke(MethodInvocation invocation) throws Throwable {
                      // TODO Auto-generated method stub
                      System.out.println("目标方法执行之前");
                      Object result = invocation.proceed();
                      System.out.println("目标方法执行之后");
                      return result;
              }
      }
    
  • 异常通知

      package com.jd.wang;
      import org.springframework.aop.ThrowsAdvice;
      public class MyThrowsAdvice implements ThrowsAdvice {
              //当目标方法抛出抛出与指定类型的类型有is-a类型时执行当前方法
              public void afterThrowing(Exception ex)
              {
                      System.out.println("执行异常通知方法");
              }
      }
    
  • 配置多个通知

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
              <bean id="someService" class="com.jd.wang.SomeService"></bean>
              <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean>
              <bean id="myBeAfterAdvice" class="com.jd.wang.MyAfterReturningAdvice"></bean>
              <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                      <property name="target" ref="someService"></property>
                      <property name="interceptorNames">
                              <array>
                                      <value>myBeforeAdvice</value>
                                      <value>myBeAfterAdvice</value>
                              </array>
                      </property>
              </bean>
      </beans>
    
  • 配置CGL代理

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
              <bean id="someService" class="com.jd.wang.SomeService"></bean>
              <bean id="myBeAfterAdvice" class="com.jd.wang.MyAfterReturningAdvice"></bean>
              <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                      <property name="target" ref="someService"></property>
                      <property name="interceptorNames" value="myBeAfterAdvice"></property>
                      <property name="proxyTargetClass" value="true"></property>
              </bean>
      </beans>
    
  • 名称匹配方法切入点顾问

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
              <bean id="someService" class="com.jd.wang.SomeService"></bean>
              <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean>
              <bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
                      <property name="advice" ref="myBeforeAdvice"></property>
                      <!-- 指定切入点 -->
                      <property name="mappedName" value="doFirst"></property> //此处可以使用通配符
              </bean>
              <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                      <property name="target" ref="someService"></property>
                      <property name="interceptorNames">
                              <array>
                                      <value>myAdvisor</value>
                              </array>
                      </property>
              </bean>
      </beans>
    
  • 正则匹配方法切入点顾问

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
              <bean id="someService" class="com.jd.wang.SomeService"></bean>
              <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean>
              <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
                      <property name="advice" ref="myBeforeAdvice"></property>
                      <!-- 指定切入点,切入点是对于方法的全限定名而言的 -->
                      <property name="patterns" value=".*doFirst,|.*doSecond"></property>
              </bean>
              <bean id= "serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
                      <property name="target" ref="someService"></property>
                      <property name="interceptorNames">
                              <array>
                                      <value>myAdvisor</value>
                              </array>
                      </property>
              </bean>
      </beans>
    
  • 默认自动代理生成器

  1. 解决代理工厂bean无法处理有多个目标bean的情况
  2. 配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
        <bean id="someService" class="com.jd.wang.SomeService"></bean>
        <bean id="someService2" class="com.jd.wang.SomeService"></bean>
        <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean>
        <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
                <property name="advice" ref="myBeforeAdvice"></property>
                <!-- 指定切入点 -->
                <property name="pattern" value=".*doFirst"></property>
        </bean>
        <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>
  • Bean名称自动代理生成器

    扫描二维码关注公众号,回复: 5122131 查看本文章
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
              http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
              <bean id="someService" class="com.jd.wang.SomeService"></bean>
              <bean id="someService2" class="com.jd.wang.SomeService"></bean>
              <bean id="myBeforeAdvice" class="com.jd.wang.MyMethodBeforeAdvice"></bean>
              <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
                      <property name="advice" ref="myBeforeAdvice"></property>
                      <!-- 指定切入点 -->
                      <property name="pattern" value=".*doFirst"></property>
              </bean>
              <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
                      <property name="beanName" value="someService"></property>
                      <property name="interceptorNames" value="myAdvisor"></property>
              </bean>
      </beans>
    

注:ProxyFactoryBean先有代理对象,将被代理对象传入代理后生成代理;自动代理基于后处理Bean,在Bean的生成过程中就会生成代理对象且把代理对象返回。

可以通过beanNames设置多个代理对象

  • AspectJ对AOP的实现

切入点表达式

  1. execution
    (
    [modifiers-pattern] 访问权限类型
    ret-type-pattern 返回值类型
    [declaring-type-pattern]全限定类型
    name-pattern(param-pattern)方法名(类型名)
    [throws-pattern] 抛出异常类型
  1. 符号的含义
符号 含义
* 0或多个任意字符
.. 用在方法参数中表示任意多个参数;用在包名后表示当前包及其子包路径
+ 用在类名后表示当前类及其子类;用在接口后表示当前接口及其实现类

定义切面

package com.jd.wang.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
        @Before("execution(* *..ISomeService.doFirst(..))")
        public void before(){
                System.out.println("执行前置通知");
        }
}

接口与类

package com.jd.wang.annotation;
public interface ISomeService {
        public void doFirst();
        public void doSecond();
}
 
package com.jd.wang.annotation;
public class SomeService implements ISomeService {
        public void doFirst() {
                // TODO Auto-generated method stub
                System.out.println("doFirst");
        }
        public void doSecond()
        {
                System.out.println("doSecond");
        }
}

测试类

package com.jd.wang.annotation;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
        @Test
        public void test01()
        {
                String resource="com/jd/wang/annotation/applicationContext.xml";
                ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
                ISomeService service = (ISomeService) ac.getBean("myService");
                service.doFirst();
                service.doSecond();
        }
}

注册

<?xml version="1.0" encoding="UTF-8"?>
<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" xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
        <bean id="myAspect" class="com.jd.wang.annotation.MyAspect"></bean>
        <bean id="myService" class="com.jd.wang.annotation.SomeService"></bean>
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

后置通知

package com.jd.wang.annotation;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
        @Before("execution(* *..ISomeService.doFirst(..))")
        public void before(){
                System.out.println("前置通知:");
        }
        @AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
        public void afteringReturning(Object result)
        {
                System.out.println("后置通知"+result);
        }
}

环绕通知

package com.jd.wang.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
        @Before("execution(* *..ISomeService.doFirst(..))")
        public void before(){
                System.out.println("前置通知:");
        }
        @AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
        public void afteringReturning(Object result)
        {
                System.out.println("后置通知"+result);
        }
        
        @Around("execution(* *..ISomeService.doFirst(..))")
        public Object myAround(ProceedingJoinPoint pjp) throws Throwable
        {
                System.out.println("执行方法之前");
                Object result = pjp.proceed();
                System.out.println("执行方法之后");
                return result;
        }
}

异常通知

package com.jd.wang.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
        @Before("execution(* *..ISomeService.doFirst(..))")
        public void before(){
                System.out.println("前置通知:");
        }
        @AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
        public void afteringReturning(Object result)
        {
                System.out.println("后置通知"+result);
        }
        
        @Around("execution(* *..ISomeService.doFirst(..))")
        public Object myAround(ProceedingJoinPoint pjp) throws Throwable
        {
                System.out.println("执行方法之前");
                Object result = pjp.proceed();
                System.out.println("执行方法之后");
                return result;
        }
        
        @AfterThrowing(value="execution(* *..ISomeService.doFirst(..))",throwing="ex")
        public void myAfterThrowing(Exception ex)
        {
                System.out.println("异常通知方法");
        }
}

最终通知

package com.jd.wang.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspect {
        @Before("execution(* *..ISomeService.doFirst(..))")
        public void before(){
                System.out.println("前置通知:");
        }
        @AfterReturning(value="execution(* *..ISomeService.doSecond(..))",returning = "result")
        public void afteringReturning(Object result)
        {
                System.out.println("后置通知"+result);
        }
        
        @Around("execution(* *..ISomeService.doFirst(..))")
        public Object myAround(ProceedingJoinPoint pjp) throws Throwable
        {
                System.out.println("执行方法之前");
                Object result = pjp.proceed();
                System.out.println("执行方法之后");
                return result;
        }
        
        @AfterThrowing(value="execution(* *..ISomeService.doFirst(..))",throwing="ex")
        public void myAfterThrowing(Exception ex)
        {
                System.out.println("异常通知方法");
        }
        
        @After(value="execution(* *..ISomeService.doFirst(..))")
        public void myAfter()
        {
                System.out.println("最终通知");
        }
  }
  • 基于XML的AOP
  1. 第一种配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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" xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
        <bean id="myAspect" class="com.jd.wang.annotation.MyAspect"></bean>
        <bean id="myService" class="com.jd.wang.annotation.SomeService"></bean>
        <!-- AOP配置 -->
        <aop:config>
                <aop:aspect ref="myAspect">
                        <aop:after method="myAfter" pointcut="execution(* *..ISomeService.doFirst(..))"/>
             <aop:after method="myAfter(org.aopalliance.intercept.Joinpoint)" pointcut="execution(* *..ISomeService.doFirst(..))"/>
                </aop:aspect>
        </aop:config>
</beans>
  1. 第二种配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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" xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->
        <bean id="myAspect" class="com.jd.wang.annotation.MyAspect"></bean>
        <bean id="myService" class="com.jd.wang.annotation.SomeService"></bean>
        <!-- AOP配置 -->
        <aop:config>
                <aop:pointcut expression="execution(* *..ISomeService.doFirst(..))" id="doFirstCut"/>
                <aop:aspect ref="myAspect">
                        <aop:after method="myAfter" pointcut-ref="doFirstCut"/>
                </aop:aspect>
        </aop:config>
</beans>

猜你喜欢

转载自blog.csdn.net/weixin_42150936/article/details/85322256