JAVA实现动态代理的两种方式

Java动态代理的2种实现方式

  1. Jdk动态代理
  2. CGLIB动态代理

JDK动态代理

JDK动态代理主要是通过java.lang.reflect.Proxy类实现的,主要是通过该类的newProxyInstance方法来创建目标类的代理对象,从而实现对目标类的功能增强。在此之前你必须创建一个实现了InvocationHandler接口的代理类,并实现它的方法invoke(),在该方法中完成对目标类的功能增强。

  • step1
    创建需要被代理的类(即需要进行功能增强的类)
/**
 * 接口类
 */
public interface UserDao {
    public void addUser();
    public void delete();
}
/**
 * 接口实现类
 */
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("添加用户");
    }
    @Override
    public void delete() {
        System.out.println("删除用户");
    }
    public void edit(){
        System.out.println("编辑用户");
    }
}
  • step2
    创建切面类(用于进行业务功能增强的类)例如:日志记录,用户权限检查等…
public class Aspect {
    public void checkPermission(){
        System.out.println("检查用户权限...");
    }
    public void recordLog(){
        System.out.println("日志记录...");
    }
}
  • step3
    创建JDK代理类
import com.study.aspect.Aspect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 创建jdk代理类 需要实现InvocationHandler接口
 */
public class JdkProxy implements InvocationHandler {

    private Object target;
    /**
     * 创建目标对象的代理对象
     * @param target
     */
    public Object creatProxy(Object target){
        this.target = target;
       
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                					  target.getClass().getInterfaces(),this);
    }
    
	/**
     * @param proxy 目标类的代理对象
     * @param method 目标类的方法
     * @param args 目标类的方法参数
     * @return 目标类的返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //创建切面类,即需要进行功能增强的类
        Aspect aspect = new Aspect();
        //目标类方法调用之前调用功能增强
        aspect.checkPermission();
        //调用被代理对象的方法 即:UserDao目标类里的方法
        Object result = method.invoke(target, args);
        //目标类方法调用之后调用功能增强
        aspect.recordLog();
        return result;
    }
}
  • step4
    JDK代理测试
public class AppTest{
    @Test
    public void testJdkProxy(){
        //创建目标对象
        UserDao userDao = new UserDaoImpl();
        //创建代理对象实例并获取增强后的userDao的代理对象
        UserDao proxy = (UserDao) new JdkProxy().creatProxy(userDao);
        // 通过代理对象调用方法 
        // proxy对象调用的方法会交给JdkProxy类的invoke()方法处理
        proxy.addUser();
        System.out.println("-------------");
        proxy.delete();
    }
}

运行结果:
运行结果
总结:

  • JDK动态代理的目标类必须继承一个或多个接口,即UserDaoImpl继承自UserDao
  • 所有生成的动态代理的对象在调用方法时都会交由invoke() 方法处理,在该方法中进行增强处理

CGLIB动态代理

CGLIB(Code Generation Libary) 是一个高性能的代码生成包,它采用非常底层的字节码技术,对指定的目标类生成一个子类,并对其子类进行增强。Enhancer类时CGLIB的核心类,通过该类create()方法创建代理对象。在此之前你必须创建一个实现了MethdoInterceptor接口的代理类,并实现它的方法intercept(),在该方法中完成对目标类的功能增强。

  • step1
    引出相关的jar包cglib-3.2.10.jar
    或者 通过maven引入
		<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.10</version>
        </dependency>
  • step2
    创建需要被代理的类(即需要进行功能增强的类)
public class UserDao2 {
    public void addUser() {
        System.out.println("添加用户");
    }
    public void delete() {
        System.out.println("删除用户");
    }
    public void edit(){
        System.out.println("编辑用户");
    }
}

  • step3
    创建切面类 (使用上面JDK动态代理step2的切面类)

  • step4
    创建CGLIB动态代理类

import com.study.aspect.Aspect;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

//继承MethodInterceptor接口并实现intercept()方法
public class CGLIBProxy implements MethodInterceptor {

    public Object createProxy(Object target){
        //创建一个动态类的对象 Enhancer是CGLIB的核心类通过它来创建代理对象
        Enhancer enhancer = new Enhancer();
        //设置父类,即设置需要进行功能增强的类
        enhancer.setSuperclass(target.getClass());
        //设置回调方法
        enhancer.setCallback(this);
        //创建代理类并返回
        return enhancer.create();
    }

	/**
     * @param proxy 目标类的代理对象
     * @param method 目标类的方法
     * @param args 目标类方法所需要的参数
     * @param methodProxy 目标类方法的代理方法对象
     * @return 目标类的返回值
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //创建切面类,即需要进行功能增强的类
        Aspect aspect = new Aspect();
        //目标类方法调用之前调用功能增强
        aspect.checkPermission();
        //调用被代理对象的方法 即:UserDao目标类里的方法
        Object result = methodProxy.invokeSuper(proxy,args);
        //目标类方法调用之后调用功能增强
        aspect.recordLog();
        return result;
    }
}
  • step5
    CGLIB代理测试
public class AppTest{

    @Test
    public void testCGLIBProxy(){
        //创建目标对象
        UserDao2 userDao = new UserDao2();
        //创建代理对象实例并获取增强后的userDao的代理对象
        UserDao2 proxy = (UserDao2) new CGLIBProxy().createProxy(userDao);
        // 通过代理对象调用方法
        // proxy对象调用的方法会交给CGLIBProxy类的intercept()方法处理
        proxy.addUser();
        System.out.println("************");
        proxy.delete();
    }

}

运行结果:
运行结果
总结:

  1. CGLIB的实现原理是通过创建目标类的子类,并对子类完成增强功能
  2. CGLIB的实现目标类无需实现任何接口
  3. 任何代理对象调用的方法都会交给MethodInterceptor的方法intercept() 去处理

注意:
1.JDK动态代理中JdkProxy类中的invoke()方法中的Object result = method.invoke(target, args); 该段代码中需要传入target(目标类对象),这的target是目标类的对象,target不可换成proxy(目标类的代理对象),否则就相当于调用代理对象的方法,而不是target对象的方法。因为只有调用proxy的方法就会调用JdkProxy类中的invoke()方法,然后Object result = method.invoke(proxy, args);的调用,又会引起JdkProxy类中的invoke() 方法,如此会造成无限循环调用,造成栈溢出异常,使程序崩溃。
2.同样,CGLIB中CGLIBProxy类中的intercept() 方法中的Object result = methodProxy.invokeSuper(proxy,args);该段代码也不能换成methodProxy.invoke(proxy,args) 和上面是同样的道理。invokeSuper() 方法是调用proxy父类的方法,因为CGLIB是对目标类创建子类完成增强,所以proxy的父类就是目标类,使用invokeSuper() 方法不会有问题。

本篇是我对java动态代理学习的笔记,欢迎各位大哥大姐批评指点。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值