Spring AOP原理及 *

作者:IT小郭. 时间:2023-06-19 18:59:56 

一、什么是代理?

指为一个目标对象提供一个代理对象, 并由代理对象控制对目标对象的引用. 使用代理对象, 是为了在不修改目标对象的基础上,增强目标对象的业务逻辑.

Spring AOP原理及 *

1、静态代理

静态代理的特点是, 为每一个业务增强都提供一个代理类, 由代理类来创建代理对象. 下面我们通过静态代理来实现对转账业务进行身份验证.

(1) 转账业务

public interface IAccountService {
   //主业务逻辑: 转账
   void transfer();
}

public class AccountServiceImpl implements IAccountService {
   @Override
   public void transfer() {
       System.out.println("调用dao层,完成转账主业务.");
   }
}

(2) 代理类

public class AccountProxy implements IAccountService {
   //目标对象
   private IAccountService target;
   public AccountProxy(IAccountService target) {
       this.target = target;
   }
   /**
    * 代理方法,实现对目标方法的功能增强
    */
   @Override
   public void transfer() {
       before();
       target.transfer();
   }
   /**
    * 前置增强
    */
   private void before() {
       System.out.println("对转账人身份进行验证.");
   }
}

(3) 测试

public class Client {
   public static void main(String[] args) {
       //创建目标对象
       IAccountService target = new AccountServiceImpl();
       //创建代理对象
       AccountProxy proxy = new AccountProxy(target);
       proxy.transfer();
   }
}

结果: 对转账人身份进行验证.调用dao层,完成转账主业务.

2、 *

静态代理会为每一个业务增强都提供一个代理类, 由代理类来创建代理对象, 而 * 并不存在代理类, 代理对象直接由代理生成工具动态生成.

2.1、JDK *

JDK * 是使用 java.lang.reflect 包下的代理类来实现. JDK * * 必须要有接口.

(1) 转账业务

public interface IAccountService {
   //主业务逻辑: 转账
   void transfer();
}
public class AccountServiceImpl implements IAccountService {
   @Override
   public void transfer() {
       System.out.println("调用dao层,完成转账主业务.");
   }
}

(2) 增强

因为这里没有配置切入点, 称为切面会有点奇怪, 所以称为增强.

public class AccountAdvice implements InvocationHandler {
   //目标对象
   private IAccountService target;

public AccountAdvice(IAccountService target) {
       this.target = target;
   }

/**
    * 代理方法, 每次调用目标方法时都会进到这里
    */
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       before();
       return method.invoke(target, args);
   }

/**
    * 前置增强
    */
   private void before() {
       System.out.println("对转账人身份进行验证.");
   }
}

(3) 测试

public class Client {
   public static void main(String[] args) {
       //创建目标对象
       IAccountService target = new AccountServiceImpl();
       //创建代理对象
       IAccountService proxy = (IAccountService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
               target.getClass().getInterfaces(),
               new AccountAdvice(target)
       );
       proxy.transfer();
   }
}

结果: 对转账人身份进行验证.调用dao层,完成转账主业务.

2.2、 CGLIB *

JDK * 必须要有接口, 但如果要代理一个没有接口的类该怎么办呢? 这时我们可以使用CGLIB * . CGLIB * 的原理是生成目标类的子类, 这个子类对象就是代理对象, 代理对象是被增强过的.

注意: 不管有没有接口都可以使用CGLIB * , 而不是只有在无接口的情况下才能使用

(1) 转账业务

public class AccountService {
   public void transfer() {
       System.out.println("调用dao层,完成转账主业务.");
   }
}

(2) 增强

因为这里没有配置切入点, 称为切面会有点奇怪, 所以称为增强.

public class AccountAdvice implements MethodInterceptor {
   /**
    * 代理方法, 每次调用目标方法时都会进到这里
    */
   @Override
   public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
       before();
       return methodProxy.invokeSuper(obj, args);
       //        return method.invoke(obj, args);  这种也行
   }

/**
    * 前置增强
    */
   private void before() {
       System.out.println("对转账人身份进行验证.");
   }
}

(3) 测试

public class Client {
   public static void main(String[] args) {
       //创建目标对象
       AccountService target = new AccountService();
       //
       //创建代理对象
       AccountService proxy = (AccountService) Enhancer.create(target.getClass(),
               new AccountAdvice());
       proxy.transfer();
   }
}

结果: 对转账人身份进行验证.调用dao层,完成转账主业务.

二、模拟Spring AOP场景

了解了 * 后, 我们就可以自己来实现Spring AOP功能了, 所以下面我们来模拟下Spring AOP场景.

(1) 转账业务

public interface IAccountService {
   //主业务逻辑: 转账
   void transfer();
}
public class AccountServiceImpl implements IAccountService {
   @Override
   public void transfer() {
       System.out.println("调用dao层,完成转账主业务.");
   }
}

(2) 切面抽象类

定义一个切面抽象类, 该类使用了模板方法的设计模式, 为开始, 结束, 异常, 前置增强, 后置增强提供了默认实现, 当我们定义切面类时只需要按需重写它们就行. isIntercept() 方法用来判断切入点是否正确, 切面类需要重写这个方法.

public abstract class BaseAspect implements MethodInterceptor {
   private static final Logger logger = LoggerFactory.getLogger(BaseAspect.class);

@Override
   public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
       Object result = null;

begin();
       try {
           if (isIntercept(method, args)) {
               before();
               result = methodProxy.invokeSuper(obj, args);
               after();
           } else {
               result = methodProxy.invokeSuper(obj,args);
           }
       } catch (Exception e) {
           logger.error("proxy failure", e);
           error(e);
           throw e;
       } finally {
           end();
       }
       return result;
   }
   /**
    * 开始增强
    */
   public void begin() {
   }
   /**
    * 切入点判断
    */
   public boolean isIntercept(Method method, Object[] args) throws Throwable {
       return true;
   }
   /**
    * 前置增强
    */
   public void before() throws Throwable {
   }

/**
    * 后置增强
    */
   public void after() throws Throwable {
   }

/**
    * 异常增强
    */
   public void error(Throwable e) {
   }

/**
    * 最终增强
    */
   public void end() {
   }
}

(3) 切面类

创建一个切面类, 类中配置切入点和增强.

public class AccountAspect extends BaseAspect {
   /**
    * 切入点
    */
   public boolean isIntercept(Method method, Object[] args) throws Throwable {
       return method.getName().equals("transfer");
   }

/**
    * 前置增强
    */
   public void before() throws Throwable {
       System.out.println("对转账人身份进行验证.");
   }
}

(4) 代理工厂类

定义一个工厂类来创建代理, 其实不创建这个类也行, 但为了模仿Spring还是创建了. @SuppressWarnings是为了抑制警告, 就是编译器上面的黄线.

public class ProxyFactory {

@SuppressWarnings("unchecked")
   public static <T> T createProxy(final Class<?> targetClass, final MethodInterceptor methodInterceptor) {
       return (T) Enhancer.create(targetClass,methodInterceptor);
   }
}

(5) 测试

public class Client {
   public static void main(String[] args) {
       //创建目标对象
       IAccountService target = new AccountServiceImpl();
       //切面
       BaseAspect accountAspect = new AccountAspect();
       //创建代理对象
       IAccountService proxy = (IAccountService) ProxyFactory.createProxy(target.getClass(), accountAspect);
       proxy.transfer();
   }
}

结果:对转账人身份进行验证.调用dao层,完成转账主业务.

来源:https://blog.csdn.net/GoodburghCottage/article/details/126931618

标签:Spring,AOP,动态,代理
0
投稿

猜你喜欢

  • Java反射机制深入理解

    2022-11-24 14:58:14
  • Java中volatile关键字实现原理

    2023-09-30 14:20:58
  • JavaWeb中的常用的请求传参注解说明

    2023-06-19 03:12:06
  • java中如何获取相关参数

    2023-11-17 20:12:39
  • 深入理解Spring中bean的生命周期介绍

    2023-02-08 17:21:37
  • Java concurrency之非公平锁_动力节点Java学院整理

    2022-07-31 22:04:37
  • JSON Web Token(JWT)原理入门教程详解

    2023-02-05 06:34:43
  • Spring Cloud Eureka 服务上下线监控的实现

    2022-02-18 21:06:15
  • java使用集合实现通讯录功能

    2023-01-30 21:27:15
  • SpringBoot 如何添加容器启动的初始化逻辑的操作方法

    2021-11-20 12:10:39
  • 浅谈SpringMVC HandlerInterceptor诡异问题排查

    2023-07-24 05:34:06
  • Java入门绊脚石之Override和Overload的区别详解

    2022-05-04 15:24:51
  • Android12四大组件之Activity生命周期变化详解

    2022-05-04 15:47:57
  • Android自定义带增长动画和点击弹窗提示效果的柱状图DEMO

    2022-10-16 17:10:25
  • java 抽象类的实例详解

    2023-06-08 05:52:40
  • Java效率提升神器jOOR

    2022-06-07 20:46:16
  • C#字符串使用密钥进行加解密

    2023-12-27 19:10:17
  • JUnit5相关内容简介

    2021-06-28 19:24:28
  • SpringBoot整合Spring Data Elasticsearch的过程详解

    2023-01-25 22:39:41
  • Windows编写jar启动脚本和关闭脚本的操作方法

    2021-05-28 04:36:58
  • asp之家 软件编程 m.aspxhome.com