传统 Spring AOP 底层实现

平常自己写代码,这个知识点用的不多,大多数时候均直接用传统 Spring AOP 自动代理,或者是 Aspect J 的注解形式。

今儿重拾一下以前学的底层基础,备忘。

基本介绍

传统 Spring AOP 底层有两种代理机制:

  • JDK 动态代理
  • CGlib 代理

关于详细介绍,互联网上已经有太多的好文章可以看了。

但是这里值得一提的有:

  • JDK 动态代理只能对实现了接口的类进行代理,CGlib采用底层的字节码技术,可以为一个类创建子类,解决无接口代理问题(**);
  • 随着 JDK 版本的升级(1.7以后),JDK 动态代理的效率已经不再比 cglib 代理模式弱,并且目前 Spring AOP 默认代理机制就是 JDK 动态代理;
  • 程序中应优先对接口创建代理,便于程序解耦维护;
  • 标记为 final 的方法不能被代理,因为无法进行覆盖;
  • Spring 只支持方法连接点,不提供属性连接点。

实两种代理模式的基本写法挺相似的,分别写两个 Demo ,日后看到也能快速记起。

代码Demo

代码目录结构

项目结构如下图:

基本配置文件介绍

maven 配置文件 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>cn.ufan0</groupId>
<artifactId>spring-aop</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
</dependencies>

<!--
指定编译JDK版本,防止出现版本报错。
我的IDEA更新到201902后,一直会出现JDK发行版本错误信息,导致无法编译。
-->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>

</project>

代理目标类

其中需要代理的类如下,JDK动态代理将对 InfoDao 接口进行代理,CGlib代理将对其实现类 InfoDaoImpl 进行代理。

InfoDao.java

package dao;

public interface InfoDao {
public void info1();
public void info2();
}

InfoDaoImpl.java

package dao.impl;

import dao.InfoDao;
import org.junit.Test;

public class InfoDaoImpl implements InfoDao {
@Test
public void info1() {
System.out.println("This is info1();");
}

@Test
public void info2() {
System.out.println("This is info2();");
}
}

具体实现代码

  • JDK 动态代理

    MyJdkProxy.java

    package demo.jdkProxy;

    import dao.InfoDao;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    public class MyJdkProxy implements InvocationHandler {
    private InfoDao infoDao;

    public MyJdkProxy(InfoDao infoDao) {
    this.infoDao = infoDao;
    }

    public Object createProxy() {
    return Proxy.newProxyInstance(infoDao.getClass().getClassLoader(), infoDao.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
    if ("info1".equals(method.getName())) {
    System.out.println("info1()已经采用 JDK动态代理;");
    return method.invoke(infoDao, objects);
    }
    return method.invoke(infoDao, objects);
    }
    }

    TestDemo.java

    package demo.jdkProxy;

    import dao.InfoDao;
    import dao.impl.InfoDaoImpl;
    import org.junit.Test;

    public class TestDemo {

    @Test
    public void test() {

    InfoDao infoDao = new InfoDaoImpl();

    InfoDao proxy = (InfoDao) new MyJdkProxy(infoDao).createProxy();

    proxy.info1();
    proxy.info2();
    }
    }
  • CGlib 代理

    MyCglibProxy.java

    package demo.cglibProxy;

    import dao.impl.InfoDaoImpl;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;

    import java.lang.reflect.Method;

    public class MyCglibProxy implements MethodInterceptor {
    private InfoDaoImpl infoDaoImpl;

    public MyCglibProxy(InfoDaoImpl infoDaoImpl) {
    this.infoDaoImpl = infoDaoImpl;
    }

    public Object createProxy() {
    // 1.创建核心类
    Enhancer enhancer = new Enhancer();
    // 2.设置父类
    enhancer.setSuperclass(infoDaoImpl.getClass());
    // 3.设置回调
    enhancer.setCallback(this);
    // 4.生成代理并返回
    return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    if ("info1".equals(method.getName())) {
    System.out.println("info1()已经采用 CGlib代理");
    return methodProxy.invokeSuper(o, objects);
    }
    return methodProxy.invokeSuper(o, objects);
    }
    }

    TestDemo.java

    package demo.cglibProxy;

    import dao.impl.InfoDaoImpl;
    import org.junit.Test;

    public class TestDemo {

    @Test
    public void test() {

    InfoDaoImpl infoDaoImpl = new InfoDaoImpl();

    InfoDaoImpl proxy = (InfoDaoImpl) new MyCglibProxy(infoDaoImpl).createProxy();

    proxy.info1();
    proxy.info2();
    }
    }
0%