• Spring AOP


    函数增强,当前有二种处理方式,

    a. 基于jdk的接口动态代理增强

    b. 基于 cglib 的父类动态代理增强

    在Spring框架中,在动态代理增加时,依据是否有接口来自动识别并实现增强

    如果有接口,将使用基于 jdk的接口动态代理,否则使用基于cglib的父类动态代理增强;

    01. 基于 jdk 动态代理增强

      >> 要求: 必须有接口;否则无法实现动态代理;

      >> 代码实现

    1 //接口
    2 public interface TargetInterface {
    3     public void save();
    4 }
    1 //接口实现
    2 public class Target implements TargetInterface {
    3     @Override
    4     public void save() {
    5         System.out.println("目标方法执行 ... ");
    6     }
    7 }
     1 //增强对象
     2 public class Advice {
     3 
     4     public void preAdvice(){
     5         System.out.println("前置增强...");
     6     }
     7 
     8     public void sufAdvice(){
     9         System.out.println("后置增强...");
    10     }
    11 }
     1 //动态代理增强
     2     public static void main(String[] args) {
     3         //目标对象
     4         Target target = new Target();
     5         //增强对象
     6         Advice advice = new Advice();
     7         //jdk的接口代理增强
     8         TargetInterface proxyInstance = (TargetInterface) Proxy.newProxyInstance(
     9                 target.getClass().getClassLoader(),
    10                 target.getClass().getInterfaces(),
    11                 new InvocationHandler() {
    12                     @Override
    13                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    14                         advice.preAdvice();
    15                         Object invoke = method.invoke(target, args);
    16                         advice.sufAdvice();
    17                         return invoke;
    18                     }
    19                 }
    20         );
    21         proxyInstance.save();
    22     }

    02.基于cglib的动态代理增强

      >> 无接口要求

      >> 代码实现 (增强对象与上面一样)

    1 //目标对象  
    2 public class Target  {
    3     public void save() {
    4         System.out.println("目标方法执行 ... ");
    5     }
    6 }
     1 //动态代理增强
     2     public static void main(String[] args) {
     3         //目标对象
     4         Target target = new Target();
     5         //增强对象
     6         Advice advice = new Advice();
     7         //cglib增强对象
     8         Enhancer enhancer = new Enhancer();
     9         //设置父类
    10         enhancer.setSuperclass(target.getClass());
    11         //设置回调
    12         enhancer.setCallback(new MethodInterceptor() {
    13             @Override
    14             public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    15                advice.preAdvice();
    16                 Object invoke = method.invoke(target, args);
    17                 advice.sufAdvice();
    18                 return invoke;
    19             }
    20         });
    21         //生成代理对象
    22         Target o = (Target) enhancer.create();
    23         o.save();
    24 
    25     }

    03. 基于Spring 配置实现动态代理增强  (目标对象带接口)

     1 // applicationContext.xml 配置
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4        xmlns:aop="http://www.springframework.org/schema/aop"
     5        xsi:schemaLocation="
     6        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     7        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
     8 ">
     9 
    10     <!--目标对象(带接口)-->
    11     <bean id="target" class="club.wuyu.proxy.AOP.Target"/>
    12     <!--目标对象(无接口)-->
    13     <bean id="targetcglib" class="club.wuyu.proxy.AOP.TargetCglib"/>
    14     <!--切面对象-->
    15     <bean id="advice" class="club.wuyu.proxy.AOP.Advice"/>
    16 
    17     <!--织入-->
    18     <aop:config>
    19         <aop:aspect ref="advice">
    20             <aop:before method="preAdvice" pointcut="execution(public void club.wuyu.proxy.AOP.Target.save())"/>
    21             <aop:after method="sufAdvice" pointcut="execution(public void club.wuyu.proxy.AOP.Target.save())"/>
    22 
    23             <aop:before method="preAdvice" pointcut="execution(public void club.wuyu.proxy.AOP.TargetCglib.save())"/>
    24             <aop:after method="sufAdvice" pointcut="execution(public void club.wuyu.proxy.AOP.TargetCglib.save())"/>
    25         </aop:aspect>
    26     </aop:config>
    27 </beans>
    //测试
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class AOPTest {
    
        @Autowired
        private TargetInterface targetInterface;
    
        @Autowired
        private TargetCglib targetCglib;
    
        @Test
        public void test02(){
            targetCglib.save();
        }
    
        @Test
        public void test01(){
            targetInterface.save();
        }
    }

    04. AOP配置说明

      

      

       >> 环绕方法的配置

         <aop:around method="around" pointcut="execution(* com.itheima.aop.*.*(..))"/> 

        

       >> 切点表达式的抽取, 便于多个不同的切点类型引用切点表达式;

        切点表达式的引用:pointcut-ref 

    05. 关于注解方式动态代理的实现

      >> 创建目标接口及目标类 (内部有目标方法);   

      >> 创建切面类 (内部有增强方法) 

      >> 将目标类和切面类做注解申明,将对象的创建权交由Spring; @Componet 注解;

        >> 在切面类中使用注解,配置织入关系   

     1 @Component("advice")    //切面类的创建权,交由Spring
     2 @Aspect                         //标识当前类为一个切面类
     3 public class Advice {
     4 
     5     @Before("execution(* club.wuyu.proxy.anno.*.*(..))") //织入
     6     public void preAdvice(){
     7         System.out.println("前置增强...");
     8     }
     9     @After("execution(* club.wuyu.proxy.anno.*.*(..))") //织入
    10     public void sufAdvice(){
    11         System.out.println("后置增强...");
    12     }
    13 }

       >> 配置文件

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4        xmlns:context="http://www.springframework.org/schema/context"
     5        xmlns:aop="http://www.springframework.org/schema/aop"
     6        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     7        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
     8        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
     9 
    10     <context:component-scan base-package="club.wuyu.proxy.anno"/>
    11 
    12     <aop:aspectj-autoproxy proxy-target-class="true"/>
    13     <!--<aop:aspectj-autoproxy/>-->
    14 
    15 </beans>

      <aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspect 切面的bean创建代理,织入切面。

      <aop:aspectj-autoproxy />的proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强。

      当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。

      如果proxy-target-class设置为false,但是目标类没有声明接口,则spring将自动使用CGLib动态代理。

      >> 关于 but was actually of type 'com.sun.proxy.$Proxy20' 错误的原因及处理

      >> 在 java 中,默认使用的动态代理是JDK基于接口的代理,如果出现上述错误,极有可能是在自动注入的时候,注入到了目标对象的实现类上,而不是目标对象的接口上;

       即:配置  <aop:aspectj-autoproxy/>

               或:配置  <aop:aspectj-autoproxy proxy-target-class="false"/>   时

          自动注入配置到了实现类上

     1 @RunWith(SpringJUnit4ClassRunner.class)
     2 @ContextConfiguration("classpath:applicationContext-anno.xml")
     3 public class AnnoTest {
     4 
     5     @Autowired
     6     private Target target;
     7 
     8     @Test
     9     public void Test01(){
    10         target.save();
    11     }
    12 }

      正确的注入,应该是接口

    1     @Autowired
    2     private TargetInterface target;

           或者,直接配置为 CGLib 动态代理, 

      即:<aop:aspectj-autoproxy proxy-target-class="true"/> 

      >> 注解方式下,切点表达式的抽取

        

        

  • 相关阅读:
    MySQL基础知识总结
    PHP常见算法
    PHP程序功能设计
    SVN配置使用及移植
    推荐一个SpringBoot + Vue + MyBatis 音乐网站项目
    累积sql常用查询语句「Oracle」
    Nginx服务器设置http/https正向代理,使用ngx_http_proxy_connect_module模块
    squid配置文件
    nginx命令
    k8s与Docker有啥关系
  • 原文地址:https://www.cnblogs.com/jieling/p/16368485.html
Copyright © 2020-2023  润新知