你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

Spring原理篇(13)--Spring AOP 的概念的实现;

2021/10/25 6:57:37

@TOC# Spring系列
记录在程序走的每一步___auth:huf


OOP表示面向对象编程,是一种编程思想,AOP表示面向切面编程,也是一种编程思想 在Spring官网中有这么一句话;
Let us begin by defining some central AOP concepts and terminology. 
These terms are not Spring-specific. Unfortunately, 
AOP terminology is not particularly intuitive. However, 
it would be even more confusing if Spring used its own terminology

其意思是:
AOP中的这些概念不是Spring特有的,不幸的是,AOP中的概念不是特别直观的,但是, 如果Spring重新定义自己的那可能会导致更加混乱

我们知道;Spring当中 有两种代理; 一种代理是JDK代理; 一种代理是CGLIB代理; 其两种代理的区别在什么地方呢? 在什么时候情况下会使用JDK 代理; 在什么情况下使用后CGLIB 代理? 这是我们必须要搞清楚的一件事情; 我们先不管什么是切面 什么是切点 什么是通知 等等 都不用详细的去看里面的源码; 我们一步一步跟着代码实践下来; 就会明白;


CGLIB

创建一个被代理类; 被代理类 就是我们经常用的Service;
在这里插入图片描述

创建代理类:
在这里插入图片描述
最后一个执行结果:
在这里插入图片描述
得到的都是CglibDemoService对象,但是执行test()方法时的效果却不一样了,这就是代理所带来的效果。上面是通过cglib来实现的代理对象的创建,是基于父子类的,被代理类(CglibDemoService)是父类,代 理类是子类,代理对象就是代理类的实例对象,代理类是由cglib创建的;

JDK代理;

JDK代理是基于接口的代理; 也就是说 被代理的一定是接口; 那么 我们就写一个接口 一个实现;
在这里插入图片描述
实现:
在这里插入图片描述
JDK 代理:
在这里插入图片描述
最后的执行结果:
在这里插入图片描述
以上就是 CGLIB 以及 JDK 代理的主要实现方式;


以下代码不以图片展示. 以图片展示 是作者希望读者能自己手动敲一遍 这样的话 可以加深对AOP的理解; 本系列文章全部代码 均是作者一个一个字母敲出来的;全部代码均自测过;

ProxyFactory

在Spring中; 针对以上两种代理进行一个封装;封装出口的类 叫做ProxyFactory 表示是创建代理对象的一个工厂,使用起来会比上面的更加方便;

package com.huf.aop;
import com.huf.aop.cglib.CglibDemoService;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
/**
 * auth : huf
 */
public class ProxyFactoryDemo {
    public static void main(String[] args) {
        CglibDemoService target = new CglibDemoService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                System.out.println("执行方法前 : before");
                Object result = methodInvocation.proceed();
                System.out.println("执行方法前 : after");
                return result;
            }
        });
        CglibDemoService cglibDemoService = (CglibDemoService) proxyFactory.getProxy();
        cglibDemoService.test();
    }
}

通过ProxyFactory,我们可以不再关系到底是用cglib还是jdk动态代理了,ProxyFactory会帮我们去 判断
如果我们 setTarget() 放进去的类 实现了接口. 那么 ProxyFactory 就会选择JDK代理 如果 不是接口 就使用CGLIB 代理; 以上就是使用的CGLIB代理的; 如果替换成为JdkDemoService 那么就是JDK代理 所以 转换出来的 是JdkDemoInterface;

在上面Proxy 类中. 我们看到 .我们添加了一个Advice 其中 Advice 就是我们的 <<通知>>

Advice 的分类

  1. Before Advice:方法之前执行
  2. After returning advice:方法return后执行
  3. After throwing advice:方法抛异常后执行
  4. After (finally) advice:方法执行完finally之后执行,这是最后的,比return更后
  5. Around advice:这是功能最强大的Advice,可以自定义执行顺序

Advisor

Advisor 我个人理解是对 Advice 的增强; 一个Advisor 里面 包含了
一个 Advice – <<通知>>
一个 Pointcut–<<切点>>
通过Pointcut可以指定要需要被代理的逻辑;

一个小的案例 可以清楚的知道Pointcut 是什么

/**
 * auth : huf
 */
public class ProxyFactoryDemo {
    public static void main(String[] args) {
        JdkDemoService jdkDemoService = new JdkDemoService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(jdkDemoService);
        proxyFactory.addAdvisor(new PointcutAdvisor() {
        	切点 切入到哪个方法中;
            @Override
            public Pointcut getPointcut() { 
                return new StaticMethodMatcherPointcut() {
                    @Override
                    public boolean matches(Method method, Class<?> aClass) {
                        return method.getName().equals("test1");
                    }
                };
            }
            @Override
            public Advice getAdvice() {
                return new MethodInterceptor() {
                    @Override
                    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                        System.out.println("方法执行前 : before");
                        Object proceed = methodInvocation.proceed();
                        System.out.println("方法执行后 : after");
                        return proceed;
                    }
                };
            }
            @Override
            public boolean isPerInstance() {
                return false;
            }
        });
        JdkDemoInterface jdkDemoInterface = (JdkDemoInterface) proxyFactory.getProxy();
        在执行 test的方法; 是不会被代理的; 因为有一个
        jdkDemoInterface.test();
        System.out.println("------------------------------------------------------------");
        在执行 test1 的方法 被代理了;
        jdkDemoInterface.test1();
    }
}

创建代理对象的方式

上面介绍了Spring中所提供了[ProxyFactory、Advisor、Advice、PointCut]等技术来实现代理对象的 创建,但是我们在使用Spring时,我们并不会直接这么去使用ProxyFactory,比如说,我们希望 ProxyFactory所产生的代理对象能直接就是Bean,能直接从Spring容器中得到UserSerivce的代理对 象,作为开发者的我们肯定得告诉Spring,那些类需要被代理,代理逻辑是什么.

以下是一个演化过程; 我们将逐步深入AOP;
我们通过ProxyBean 进行 Bean的注册;

ProxyFactoryBean

    @Bean
    public ProxyFactoryBean proxyFactoryBean() {
        CglibDemoService cglibDemoService = new CglibDemoService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(cglibDemoService);
        proxyFactoryBean.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                System.out.println("方法执行前 : before");
                Object proceed = methodInvocation.proceed();
                System.out.println("方法执行后 : after");
                return proceed;
            }
        });
        return proxyFactoryBean;
    }

在这里插入图片描述
执行结果是 :

在这里插入图片描述
继续演进; 我们可以 将 advice 单独注册;

 @Bean
    public MethodInterceptor hufAroundAdvise() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("方法执行前 : before");
                Object proceed = invocation.proceed();
                System.out.println("方法执行后 : after");
                return proceed;
            }
        };
    }
    @Bean
    public ProxyFactoryBean proxyFactoryBean() {
        CglibDemoService cglibDemoService = new CglibDemoService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(cglibDemoService);
        proxyFactoryBean.setInterceptorNames("hufAroundAdvise");
        return proxyFactoryBean;
    }

他们的执行结果是一模一样的 仅仅是将 advice 注册成为了Bean;

继续往下深挖; 我们既然可以注册一个 那么 我们是否可以批量注册??

BeanNameAutoProxyCreator

两个普通的Service
@Component
public class CglibDemoService {
    public void test(){
        System.out.println("CGLIB 动态代理演示;");
    }
}

@Component
public class CglibDemoService2 {
    public void test(){
        System.out.println("CGLIB2 动态代理演示;");
    }
}
@Configuration
public class AopConfig {
    @Bean
    public MethodInterceptor hufAroundAdvise() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("方法执行前 : before");
                Object proceed = invocation.proceed();
                System.out.println("方法执行后 : after");
                return proceed;
            }
        };
    }
    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames("cglibDemoServic*");
        beanNameAutoProxyCreator.setInterceptorNames("hufAroundAdvise");
        beanNameAutoProxyCreator.setProxyTargetClass(true);
        return beanNameAutoProxyCreator;
    }
}

执行:
在这里插入图片描述

结果:
在这里插入图片描述
这个方法虽然可行 但是只能通过Class Name 进行代理 继续往下深挖

DefaultAdvisorAutoProxyCreator

@Bean
    public MethodInterceptor hufAroundAdvise() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("方法执行前 : before ....");
                Object proceed = invocation.proceed();
                System.out.println("方法执行后 : after....");
                return proceed;
            }
        };
    }

    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor(MethodInterceptor hufAroundAdvise){
        NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
        nameMatchMethodPointcut.addMethodName("test"); //切入的方法名字
        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(nameMatchMethodPointcut);//注入切点
        defaultPointcutAdvisor.setAdvice(hufAroundAdvise);//注入切点逻辑
        return defaultPointcutAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        return defaultAdvisorAutoProxyCreator;
    }

通过DefaultAdvisorAutoProxyCreator会直接去找所有Advisor类型的Bean,根据Advisor中的 PointCut和Advice信息,确定要代理的Bean以及代理逻辑.

这样 我们把所有本章节所有Bean注册进容器;包括JDK代理的Bean 也注册进去;

执行:
在这里插入图片描述
得到的执行结果:
在这里插入图片描述
这样 我们就进行了 更深层次的演化;


总结:

本章节一共讲解了

  1. CGLIB的实现
  2. JDK 动态代理的实现;
    介绍了AOP 的
  3. Pointcut —切点
  4. Advice —通知
  5. Advisor —前面两个的结合;
    介绍了实体类
  6. ProxyFactory —Spring使用的
  7. ProxyFactoryBean --注册进入Spring容器中的.生成单个的bean
  8. BeanNameAutoProxyCreator – 通过类名字 批量生产代理对象
  9. DefaultAdvisorAutoProxyCreator – 通过方法名字 批量生产代理对象

下个章节 将会对AOP 进行源码讲解; AOP本身不难. 所以它的源码 要比之前的文章的要简单; 并且有了这篇文章的一个铺垫; 可以说直接起飞;

seeyou