静态代理?动态代理?Cglib代理?

有不够细致的地方或者想讨论的可以在评论区留言

 

生活中常见的示例

明星的经纪人,第三方无法直接与某明星接触,只能联系经纪人,经纪人可以代为某明星进行一些事情的处理

 

Java中代理常分以下三种

  • 静态代理: 核心理解->持有target,编码在target的方法前后进行处理

  • 动态代理:核心理解->代理对象proxy和被代理对象target要实现共同的接口

  • Cglib代理:核心理解->为被代理对象target生成子类,子类即为proxy

 

静态代理

创建一个测试IUserDao

public interface IUserDao {
    public void save();
}

创建一个测试UserDao

public class UserDao implements IUserDao {
    public void save(){
        System.out.println("测试保存数据=======");
    }
}

创建静态代理对象

public class StaticProxyUserDao implements IUserDao {

    //持有被代理对象
    private UserDao userDao;

    public StaticProxyUserDao(UserDao userDao){
        this.userDao = userDao;
    }

    @Override
    public void save() {

        System.out.println("目标方法执行前的处理。。。。。。。。。。");
        //执行被代理对象的方法
        userDao.save();

        System.out.println("目标方法执行后的处理。。。。。。。。。。。");
    }
}

总结

静态代理,target和proxy都需要实现共同的接口,且proxy需要持有target,可以以构造器的方式。

 

动态代理

动态代理为何代理对象proxy和被代理对象target要实现共同的接口?

 

先从源码分析中查看JDK对动态代理的支持类java.lang.reflect.Proxy, 该类下有newProxyInstance()方法来创建代理对象,注意该方法中的第二个入参Class<?>[] interfaces 表示被代理类target的接口类型,因此需要target要实现某个接口

@CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
{
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

        /*
         * Look up or generate the designated proxy class.
         */
        Class<?> cl = getProxyClass0(loader, intfs);

        /*
         * Invoke its constructor with the designated invocation handler.
         */
        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

示例

在上一步静态代理中已经创建了IUserDao和UserDao,可以复用

在次创建JDK动态代理​​​​​​​

public class JdkProxyFactory {

    private Object target;

    //构造方法注入target
    public JdkProxyFactory(Object target){
        this.target = target;
    }

    /**
     * 创建代理对象
     * @return
     */
    public Object getProxyInstance(){
        //使用Proxy的newProxyInstance方法
        return Proxy.newProxyInstance( 
                target.getClass().getClassLoader(),//target的类加载器
                target.getClass().getInterfaces(),//target的接口类型
                new InvocationHandler() { //InvocationHandler 很好理解,即在代理对象proxy中对target方法的额外处理
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("目标方法执行前的处理。。。。。。。。。。。。。。");

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

                        System.out.println("目标方法执行后的处理。。。。。。。。。。");
                        return returnValue;
                    }
                });

    }

}

JDK动态代理测试

public class JdkProxyTest {

    public static void main(String[] args) {
        IUserDao target = new UserDao();
        System.out.println("userDao.getClass() = " + target.getClass());

        IUserDao proxy = (IUserDao) new JdkProxyFactory(target).getProxyInstance();
        System.out.println("proxy.getClass() = " + proxy.getClass());

        //调用代理对象的方法
        proxy.save();
    }
}

结果

​​​​​​​

userDao.getClass() = class com.coolcoding.boot.proxy.UserDao
proxy.getClass() = class com.sun.proxy.$Proxy0
目标方法执行前的处理。。。。。。。。。。。。。。
测试保存数据=======
目标方法执行后的处理。。。。。。。。。。

 

Cglib代理

核心理解:为被代理对象target生成子类,底层使用字节码处理框架ASM,有兴趣可以自己深入研究ASM

 

创建代理对象​​​​​​​

/**
 * 首先要实现org.springframework.cglib.proxy.MethodInterceptor 
 * 
 * 
 * Cglib代理方式总结:
 * 1.目标类不能为final,否则抛异常报错
 * 2.目标类的方法如果为final, static, 则子类无法重写,则不会被代理对象拦截。
 *
 *
 * Create by Administrator on 2020/5/14 10:57
 */
public class CglibProxyFactory implements MethodInterceptor {

    private Object target;

    //通过构造器注入target
    public CglibProxyFactory(Object target){
        this.target = target;
    }

    @Override
    public Object intercept(Object o,
                            Method method,
                            Object[] args,
                            MethodProxy methodProxy) throws Throwable {
        System.out.println("目标方法执行前的处理。。。。。。。。。。。。。。");
        Object returnValue = method.invoke(target, args);
        System.out.println("目标方法执行后的处理。。。。。。。。。。");
        return returnValue;
    }

    /**
     * 创建cglib代理对象
     * @return
     */
    public Object getProxyInstance(){
        //使用org.springframework.cglib.proxy.Enhancer
        Enhancer enhancer = new Enhancer();
        //设置父类类型 -> 对应核心理解中的为target创建子类
        enhancer.setSuperclass(target.getClass());
        //设置回调方法,则调用时会触发该类中的intercept方法
        enhancer.setCallback(this);
        //创建代理对象 即子类
        return enhancer.create();
    }
}

Cglib测试

UserDao2 与UserDao一致,唯一区别是UserDao2没有实现接口,因为Cglib不需要target实现接口

​​​​​​​

public class CglibTest {

    public static void main(String[] args) {

        //生成一个目标对象
        UserDao2 target = new UserDao2();
        System.out.println("userDao.getClass() = " + target.getClass());

        //创建代理对象
        UserDao2 proxy = (UserDao2) new CglibProxyFactory(target).getProxyInstance();
        System.out.println("proxy.getClass() = " + proxy.getClass());
        //执行代理对象的方法
        proxy.save();
    }
}

Cglib结果​​​​​​​​​​​​​​

userDao.getClass() = class com.coolcoding.boot.proxy.UserDao2
proxy.getClass() = class com.coolcoding.boot.proxy.UserDao2$$EnhancerByCGLIB$$74c2897e
目标方法执行前的处理。。。。。。。。。。。。。。
保存数据....cglib....
目标方法执行后的处理。。。。。。。。。。

Cglib总结:

  1. Cglib中target不能为final类型,因为final类型的类无法为其创建子类

  2. target中的方法不能为final或者static,虽然可以正常运行,但是由于方法无法被子类重写,而不会被代理对象拦截。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值