Spring Aop - Aop概念以及代理模式-第七篇

什么是Aop?

AOP是Aspect-Oriented Programming(面向方面编程或面向切面)的简称,最主要的是从业务代码中找到关键的关注点,并分离关注点,使解决特定领域问题(日志,监控)的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。

Aop相关技术:

  • AsepectJ,源代码级别和字节码级别。
  • Javassit,Java字节码操作类。
  • java instrument,虚拟机级别的Aop,监控用的比较多,例如各种agent。

Aop联盟定义的Aop体系架构:

       “基础”(base)可以视为待增强对象或者说目标对象;“切面”(aspect)通常包含对于基础的增强应用“配置”(configuration)可以看成是一种编织,通过在AOP体系中提供这个配置环境,可以把基础和切面结合起来,从而完成切面对目标对象的编织实现。

Spring Aop内核心概念

Advice 通知

Advice(通知)定义在连接点做什么,为切面增强提供织入接口。在Spring AOP中,它主要描述Spring AOP围绕方法调用而注入的切面行为。Advice是AOP联盟定义的一个接口,具体的接口定义在org.aopalliance.aop.Advice中。在Spring AOP的实现中,使用了这个统一接口,并通过这个接口,为AOP切面增强的织入功能做了更多的细化和扩展,比如提供了更具体的通知类型,如BeforeAdvice、AfterAdvice、ThrowsAdvice等。

PointCut 切点

Pointcut(切点)决定Advice通知应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法的集合,这些集合的选取可以按照一定的规则来完成。在这种情况下,Pointcut通常意味着标识方法,例如,这些需要增强的地方可以由某个正则表达式进行标识,或根据某个方法名进行匹配等。

Advisor通知器

完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象把它们结合起来,完成这个作用的就是Advisor(通知器)。通过Advisor,可以定义应该使用哪个通知并在哪个关注点使用它,也就是说通过Advisor,把Advice和Pointcut结合起来,这个结合为使用IoC容器配置AOP应用,或者说即开即用地使用AOP基础设施,提供了便利。

在Spring内org.springframework.aop.support.DefaultPointcutAdvisor可以用来结合Advice和PointCut,此类有两个属性,一个是Advice一个是PointCut,很简单清晰。

代理设计模式

代理设计模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

维基百科官方实例:

我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。ProxyPatternDemo,我们的演示类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。

public interface Image {
   void display();
}
public class RealImage implements Image {
 
   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 
   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }
 
   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}
public class ProxyImage implements Image{
 
   private RealImage realImage;
   private String fileName;
 
   public ProxyImage(String fileName){
      this.fileName = fileName;
   }
 
   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}
public class ProxyPatternDemo {
   
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");
 
      // 图像将从磁盘加载
      image.display(); 
      System.out.println("");
      // 图像不需要从磁盘加载
      image.display();  
   }
}

JDK动态代理

JDK动态代理模式,通过反射和拦截进行实现,主要有以下几个要求:

1.被代理的类必须实现接口。

2.通过Proxy.newProxyInstance来生成代理类。

3.需要实现InvocationHandler接口。

具体的例子:

public interface RiskService {

    void execute();

    void execute(String str);


}
public class RiskServiceImpl implements RiskService {

    @Override
    public void execute() {
        System.out.println("execute risk service");
    }

    @Override
    public void execute(String str) {
        System.out.println("execute risk service" + str);
    }
}
public class RiskServiceInvocation implements InvocationHandler {

    private Object target;

    public RiskServiceInvocation(Object target) {
        this.target = target;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("执行前置操作");
        System.out.println(args.toString());
        Object result = method.invoke(target, args);
        System.out.println("执行后置操作");
        return result;
    }
}
public class ProxyRiskTest {

    public static void main(String[] args) {
        RiskService riskService = (RiskService) Proxy.newProxyInstance(RiskService.class.getClassLoader(), new Class[]{
                RiskService.class }, new RiskServiceInvocation(new RiskServiceImpl()));
        riskService.execute(" str");
    }

结论:JDK只能生成接口实现的代理类,在某些使用场景下,不足够灵活,下面可以看下使用Cglib代理。

Cglib动态代理

public class RiskServiceImplCglibProxy implements MethodInterceptor {


    public Object createInstance(Object target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib开始");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("cglib结束");
        return invokeSuper;
    }
}
public class ProxyRiskTest {

    public static void main(String[] args) {
       /* RiskService riskService = (RiskService) Proxy.newProxyInstance(RiskService.class.getClassLoader(), new Class[]{
                RiskService.class }, new RiskServiceInvocation(new RiskServiceImpl()));
        riskService.execute(" str");*/
        RiskServiceImplCglibProxy cglibProxy = new RiskServiceImplCglibProxy();
        RiskServiceImpl proxyInstance = (RiskServiceImpl) cglibProxy.createInstance(new RiskServiceImpl());
        proxyInstance.execute();
    }

}

总结

Aop即面向切面编程,本质上解决的问题是,将一些有别于业务的逻辑的代码,从业务代码中剥离出来,进行统一的封装和维护。再通过代理设计模式的思想,利用jdk动态代理技术或者cglib技术,通过定义出切点(要执行的哪段逻辑代码,一般是方法维度),通过定义通知(前置,后置,环绕等),再通过通知器把两者给捏合起来。来达到既能执行业务逻辑代码又能执行特定代码的目的。从另一个维度去看,Aop本质上也是解耦和内聚,对不关联逻辑解耦,对关联逻辑内聚。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值