欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring AOP 代理实现的两种方式: JDK动态代理 和 Cglib框架动态代理

程序员文章站 2022-07-12 14:30:02
...

1.JDK动态代理

JDK API 内置 ---- 通过 Proxy类,为目标对象创建代理 (必须面向接口代理 ),此文中接口为UserDao,实现类为UserDaoImpl.

public class UserDaoImpl implements UserDao {

    @Override
    public void save() {
        System.out.println("保存方法执行");

    }

}

下面为目标对象target(UserDaoImpl)创建代理的工厂:

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

public class JdkProxyFactory{
    //被代理的对象
    private Object target;
    
    public JdkProxyFactory(Object target) {
        this.target = target;
    }
    
    /**
     * 用于创建target的代理对象
     * @return
     */
    public Object createProxy(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //运行增强的方法
                System.out.println("方法增强了");
                //运行被代理对象的真正方法
                return method.invoke(target, args);
            }
        });
    }

}
下面为测试类,为UserDaoImpl创建代理对象,对用代理对象执行UserDaoImpl中的方法

public class JdkProxyTest {
    @Test
    public void testUseProxy(){
        //代理之前的对象
        UserDao userDao = new UserDaoImpl();
        //代理之后的对象
        UserDao userDaoProxy = (UserDao) new JdkProxyFactory(userDao).createProxy();
        System.out.println(userDaoProxy);
        userDaoProxy.save();
    }

}

缺点: 使用Jdk动态代理,必须要求target目标对象,实现接口 ,如果没有接口,不能使用Jdk动态代理


2.Cglib 动态代理

CGLIB(CodeGeneration Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。

Cglib 不但可以对接口进行代理,也可以对目标类对象,实现代理(解决了 Jdk 只能对接口代理问题 )。在spring3.2版本 core包中内置cglib 类。

下面为ProductDao使用cglib为其创建代理对象

public class ProductDao {
    
    public void saveProdcut(){
        System.out.println("产品保存");
    }

}

创建代理对象的工厂:

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * 使用cglib进行代理 --- 工厂类
 * 
 */
public class CglibProxyFactory implements MethodInterceptor {
	// 被代理目标对象
	private Object target;

	// 在构造工厂时传入被代理对象
	public CglibProxyFactory(Object target) {
		this.target = target;
	}

	// 创建代理对象方法
	public Object createProxy() {
		// 1、 创建Enhancer对象
		Enhancer enhancer = new Enhancer();

		// 2、 cglib创建代理,对目标对象,创建子类对象
		enhancer.setSuperclass(target.getClass());

		// 3、传入 callback对象,对目标增强
		enhancer.setCallback(this);

		return enhancer.create();
	}

	@Override
	/**
	 * proxy 代理对象
	 * method 当前调用方法
	 * args 方法参数
	 * methodProxy 被调用方法代理对象 (作用:执行父类的方法)
	 */
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		System.out.println("记录日志......");
		// 按照JDK编程
		// return method.invoke(target, args);
		return methodProxy.invokeSuper(proxy, args);
	}
}


下面为测试类:

import org.junit.Test;

public class CglibProxyTest {
    @Test
    public void test(){
        ProductDao productDao = new ProductDao();
        ProductDao productDaoProxy = (ProductDao) new CglibProxyFactory(productDao).createCglibProxy();
        productDaoProxy.saveProdcut();
    }
}

运行结果如下:

Spring AOP 代理实现的两种方式: JDK动态代理 和 Cglib框架动态代理

Cglib 创建代理思想:对目标类创建子类对象

       设置 superClass 对哪个类创建子类 (类似 JDK代理 接口)

       设置 callback 实现增强代码 (类似 JDK代理InvocationHandler )

 

在cglib的callback函数中,要执行被代理对象的方法

       method.invoke(target,args); 等价于 methodProxy.invokeSuper(proxy,args); 


Spring AOP 代理实现的两种方式: JDK动态代理 和 Cglib框架动态代理

优先对接口代理(使用JDK代理),如果目标没有接口,才会使用cglib代理