软件编程
位置:首页>> 软件编程>> java编程>> Spring AOP原理及 *

Spring AOP原理及 *

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

标签:Spring,AOP,动态,代理

一、什么是代理?

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

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

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com