Spring AOP 分析(一)

Spring AOP 分析(一)

一、前提

  • 本文基于spring-aop包5.3.20版本作为前提。
  • spring-aop是一种编程思想,aop是指使用切面方式进行编程,简单来说就是在一个方法执行前和执行后做处理。

二、基础知识

代理方式

  1. 静态代理

    代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。
    
  2. 动态代理

    静态代理的代理类需要实现与目标类一样的接口。而动态代理不需要。只需要实现InvocationHandler类;
    同时分为两种代理方式:
    	jdk动态代理(Proxy类和InvocationHandler接口来实现动态代理)
    	cglib动态代理(继承MethodInterceptor类使用Enhancer类创建代理对象)
    

spring-aop中基础术语

  • Aspect:切面。比如被@Aspect注解的类就是切面,理解为记录关系的类。
  • Join point:连接点。可以理解为程序里面的一个方法的执行。
  • Advice:通知。在指定的连接点执行的动作时机,理解为一个方法;同时Advice分为不同的类型(before、after、around),Spring框架中会用Interceptor拦截器来实现Advice,每个连接点对应一个Interceptor链。
  • Pointcut:切点。用来匹配一个或多个连接点,Advice与切点表达式是关联在一起的,Advice将会执行在和切点表达式所匹配的连接点上。
  • Weaving:织入。创建代理对象的动作,这个动作可以发生在编译时期(比如Aspejctj),或者运行时,比如Spring AOP。
  • Target object:目标对象,被代理的对象。
  • advistor:顾问。包含一个Pointcut和一个advice,而aspect可以多个pointcut和多个advice。理解为把advice和Pointcut封装成一个advistor。

advice在spring-aop中对应的类

  • @Before:AspectJMethodBeforeAdvice,实际上就是一个MethodBeforeAdvice。
  • @AfterReturning:AspectJAfterReturningAdvice,实际上就是一个AfterReturningAdvice。
  • @AfterThrowing:AspectJAfterThrowingAdvice,实际上就是一个MethodInterceptor。
  • @After:AspectJAfterAdvice,实际上就是一个MethodInterceptor。
  • @Around:AspectJAroundAdvice,实际上就是一个MethodInterceptor

关系图

关系图

左边类实现右边的类:

AspectJAfterAdvice->MethodInterceptor, AfterAdvice
AspectJAfterThrowingAdvice->MethodInterceptor, AfterAdvice
AspectJAroundAdvice->MethodInterceptor

AspectJMethodBeforeAdvice->MethodBeforeAdvice->BeforeAdvice
AspectJAfterReturningAdvice->AfterReturningAdvice->AfterAdvice

前面3个实现的原理就是依赖MethodInterceptor,后面两个分别依赖MethodBeforeAdviceInterceptorAfterReturningAdviceInterceptor,但是这两个还是实现了MethodInterceptor。因此它们会组成一条Interceptor链路。

三、代码例子

静态代理

/**
 * @description: 共同业务接口
 * @author: gongjuncheng
 **/
public interface ICommonService {
    void add(String name);
}

/**
 * @description: 被代理类,实现同一接口
 * @author: gongjuncheng
 **/
@Service
public class TargetServiceImpl implements ICommonService {
    @Override
    public void add(String name) {
        System.out.println("向数据库中插入名为:  "+name+" 的用户");
    }
}


/**
 * @description: 代理类,并且实现同一接口
 * @author: gongjuncheng
 **/
public class ProxyServiceImpl implements ICommonService {

    /**
     * 被代理对象(目标对象)
     */
    private ICommonService target;

    /**
     * 通过构造方法注入被代理对象
     * @param object
     */
    public ProxyServiceImpl(ICommonService object){
        this.target = object;
    }

    @Override
    public void add(String name){
        System.out.println("准备向数据库中插入数据");
        target.add(name);
        System.out.println("插入数据库成功");
    }
}

/**
 * @description: 测试静态代理
 * @author: gong juncheng
 */
public class ProxyTestStatic {
    /**
     * 代理模式---静态代理
     */
    public static void main(String[] args) {
        // 实例化需要被代理的类
        ICommonService target = new TargetServiceImpl();
        // 通过代理类对目标类进行代理,其实就是额外对目标类的某个方法进行特殊处理,添加点东西而已
        ProxyServiceImpl proxy = new ProxyServiceImpl(target);
        // 调用代理类的方法,该方法就是目标类的方法。
        proxy.add("123");
    }
}

动态代理

jdk动态代理
/**
 * @description: 实现接口动态代理-接口
 * @author: gong juncheng
 */
public interface Subject {

    void add(String name);

    void say(String msg);
}

/**
 * @description: 实现接口动态代理-实现类
 * @author: gong juncheng
 */
@Service
public class SubjectImple implements Subject {
    @Override
    public void add(String name) {
        System.out.println("向数据库中插入名为:  "+name+" 的用户");
    }

    @Override
    public void say(String msg) {
        System.out.println("hello world,"+msg);
    }
}

/**
 * @description: 实现接口动态代理-代理工具类
 * @author: gong juncheng
 */
public class ProxyInvocationHandler implements InvocationHandler {

    /**
     * 被代理的目标类
     */
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在目标对象的方法执行之前简单的打印一下
        System.out.println("------------------before------------------");

        // 执行目标对象的方法
        Object result = method.invoke(target, args);

        // 在目标对象的方法执行之后简单的打印一下
        System.out.println("-------------------after------------------");

        return result;
    }

    /**
     * 获取被代理的目标类的代理对象
     */
    public Object getProxy(){

        return Proxy.newProxyInstance(this.target.getClass().getClassLoader()
                ,this.target.getClass().getInterfaces()
                ,this);
    }
}

/**
 * @description: 实现接口动态代理-测试启动类
 * @author: gong juncheng
 */
public class ProxyTestDynamicInterface {
    /**
     * 代理模式---JDK动态代理
     */
    public static void main(String[] args) throws IOException {
        // 使用传统的代理类实现InvocationHandler接口,再通过Proxy类的静态方法创建代理类
		// 1.实例化等待被代理的实现类
        Subject subject = new SubjectImple();
        // 2.实例化InvocationHandler 代理处理器
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(subject);
        // 3.根据被代理实现类生成代理对象,这个getProxy方法可以不写在ProxyInvocationHandler里面,在这里写,ProxyInvocationHandler就可以给多个需要代理的方法共用。
        Subject proxySubject = (Subject) proxyInvocationHandler.getProxy();
        System.out.println("代理类路径:"+proxySubject.getClass());
        proxySubject.add("熊大");
        proxySubject.say("my home");
    }
}
cglib动态代理
/**
 * 被代理类
 * @author gongjuncheng
 */
public class SourceClass {

    void go() {
        System.out.println("进击的巨人....");
    }

    void sleep() {
        System.out.println("全世界阔以安息了...");
    }
}


/**
 * cglib动态代理的执行类
 * @author gongjuncheng
 */
public class CglibProxyHandle{

    /**
     * 被代理类
     */
    private Object target;
    /**
     * cglib的拦截器
     */
    private MethodInterceptor methodInterceptor;

    public CglibProxyHandle(Object target, MethodInterceptor methodInterceptor) {
        this.target = target;
        this.methodInterceptor = methodInterceptor;
    }

    /**
     * 获取被代理的目标类的代理对象
     */
    public Object getProxy(){
        Enhancer enhancer = new Enhancer();
        // 设置代理类的父类
        enhancer.setSuperclass(target.getClass());
        // 设置代理逻辑
        enhancer.setCallback(methodInterceptor);
        // 创建代理对象
        return enhancer.create();
    }
}

/**
 * cglib的拦截器,真正处理被代理类的上下文操作
 * @author gongjuncheng
 */
public class CglibProxyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (method.getName().equals("go")){
            System.out.println("艾伦耶格尔开始出现");
            methodProxy.invokeSuper(o,objects);
            System.out.println("大家快跑啊!!!!");
            return null;
        }

        return methodProxy.invokeSuper(o, objects);
    }
}

/**
 * @author gongjuncheng
 */
public class Test {
    public static void main(String[] args) {
        CglibProxyHandle proxyHandle = new CglibProxyHandle(new SourceClass(),new CglibProxyMethodInterceptor());
        SourceClass sourceClass = (SourceClass) proxyHandle.getProxy();
        System.out.println("生成的代理类的路径:"+sourceClass.getClass());
        sourceClass.go();
        sourceClass.sleep();
    }
}

四、总结

本文主要介绍了AOP的一些基本知识,动态代理中jdk代理和cglib代理的不同,以及代码的实现。

下文会讲会涉及部分源码知识点,敬请期待~~~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值