您现在的位置是:首页 >技术教程 >SpringAOP 原理分析网站首页技术教程

SpringAOP 原理分析

qq_34350368 2026-03-24 00:01:04
简介SpringAOP 原理分析

#Spring AOP
Spring AOP 的核心思想是面向切面,面向切面这个思想对于编程经验少的人很难理解,下面通过分析Spring AOP的原理来深刻的体会。

  1. 静态代理
  2. JDK动态代理
  3. CGLIB动态代理

一 静态代理

假设我们有一个数据服务DataService,这个服务两个方法:add(), del()

现在有一个类DataServiceImplA实现了这个服务,并且有一个代理类通过实现类DataServiceImplA来代理这个服务。

那么我们可以写代码:

//数据服务
interface DataService{
	void add();
	void del();
}

//实现类
class DataServiceImplA implements DataService{
	@Override
	public void add(){
		System.out.println("add");
	}
	@Override
	public void del(){
		System.out.println("del");
	}
}

//代理类
class DataServiceProxy implements DataService{
	DataServiceImplA server = new DataServiceImplA();
	@Override
	public void add(){
		server.add();
		//自定义的内容
		System.out.println("代理执行add方法,添加到日志")
	}
	@Override
	public void del(){
		server.del();
		//自定义的内容
		System.out.println("代理执行del方法,添加到日志")
	}
}

//程序入口
public class StaticProxy{
	public static void main(String[] args){
		DataService service = new DataServiceProxy();
		service.add();
		service.del();
	}
}

上面的代理方式就是静态代理,这种方式有什么问题呢?它的拓展性很差!

如果有个类DataServiceImplB也实现了数据服务DataService, 需要为其创建一个新的代理类来重写DataServiceImplB中的方法

二 JDK动态代理

使用上面那个例子, 利用Java中的反射,来实现动态代理。
数据服务类和实现类不再重复。

class ProxyInvocationHandler implements InvocationHandler {
    private DataService service;

    public ProxyInvocationHandler(DataService service) {
        this.service = service;
    }

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理类方法调用之前,进行自定义操作");

        Object res = method.invoke(service,args);

        System.out.println("代理类方法调用之后,进行自定义操作");
        return res;
    }
}

public class DynamicProxy {
    public static void main(String[] args) {
        //创建服务类
        DataService serviceA = new new_DataServiceImplA();

        //将实现了接口的服务类serviceA传入到代理Handler中,然后拿到服务类的代理
        DataService serviceProxy = (DataService) new ProxyInvocationHandler(serviceA).getDataServiceProxy();

        //代理类执行服务类的方法
        serviceProxy.add();
        serviceProxy.del();
    }
}

可以看到这里有一个代理调用处理器类,这个类中有一个私有的数据服务属性, 构造方法将外部传入的方法赋给私有的方法。

getDataServiceProxy()方法创建代理对象。

当调用代理对象的方法时,会自动调用invoke()方法,可以在invoke()方法中添加处理逻辑,实现方法的调用,拦截和增强。

在这个代码中,很多都写死了,比如代理调用处理器类中的私有属性DataService,这里可以用Object来代替,

以上的代码可以改为:

class ProxyInvocationHandler implements InvocationHandler {
    private Object target;

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

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理类方法调用之前,进行自定义操作");

        Object res = method.invoke(service,args);

        System.out.println("代理类方法调用之后,进行自定义操作");
        return res;
    }
}

public class DynamicProxy {
    public static void main(String[] args) {
        //创建服务类
        DataService serviceA = new new_DataServiceImplA();

        //将实现了接口的服务类serviceA传入到代理Handler中,然后拿到服务类的代理
        DateService serviceProxy = (DateService) new ProxyInvocationHandler(serviceA).getTargetServiceProxy();

        //代理类执行服务类的方法
        serviceProxy.add();
        serviceProxy.del();
    }
}

三 CGLIB动态代理

JDK动态代理有什么缺点吗?
JDK动态代理要求代理的对象类必须实现接口。这一点是一个限制。

在这里使用一个新例子,假设当前我们有个拥有发送短信方法的类。

CGLIB动态代理如何代理这个类呢?

//具有短信功能的类
class SmsService{
    public String sendSms(String phoneNumber, String message){
        System.out.println("send message: "+message+"to "+phoneNumber);
        return message;
    }
}


/**
 * 定义一个方法拦截器用来实现动态代理
 **/
class DebugMethodsInterceptor implements MethodInterceptor{

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("在调用方法之前,执行自定义操作");
        Object object = methodProxy.invoke(o, args);
        System.out.println("在调用方法之后,执行自定义操作");
        return object;
    }
}

class CglibProxyFactory{
    public static Object getServiceProxy(Class<?> clazz){
        //创建动态代理增强类
        Enhancer enhancer = new Enhancer();

        //设置加载器
        enhancer.setClassLoader(clazz.getClassLoader());

        //设置被代理类
        enhancer.setSuperclass(clazz);

        //设置方法拦截器
        enhancer.setCallback(new DebugMethodsInterceptor());

        return enhancer.create();
    }
}
public class CGLIBProxy {
    public static void main(String[] args) {
        SmsService smsService = (SmsService) CglibProxyFactory.getServiceProxy(SmsService.class);

        smsService.sendSms("123456789", "Hello World");
    }
}

首先有个方法拦截器类,这个拦截器用来拦截发送短信的方法,在方法调用前后进行一系列处理,例如日志,鉴权等。
接下来是代理工厂类,代理工厂类有创建代理的方法,传入参数是被代理的目标类的class。Enhancer类是创建代理对象的核心类。setClassLoader方法用来设置代理类的类加载器,使用目标类的类加载器。 setSuperclass方法设置被代理的类,CGLIB通过继承目标类来代理对象。 setCallback方法设置拦截器,当代理对象调用目标方法的时候,触发拦截方法。

反思

Spring AOP 的核心目标是在不修改目标对象代码的前提下,对目标对象的方法进行增强,例如增加日志,鉴权,事务管理等。为了实现这个目标,Spring AOP通过在运行时创建代理对象来拦截目标对象的方法调用,并在方法调用前后插入额外逻辑。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。