Java 代理


Java的代理实现模式有三种,分别为 静态代理、Proxy动态代理、cglib动态代理

Spring AOP面向切面编程就是用动态代理来实现的,在目标类的基础上,生成增强目标类(目标函数执行之前BeforeAdviseInterceptor、执行之后AfterAdviseInterceptor、抛出异常是执行ThrowsAdviseInterceptor)。

1.静态代理

/**
 * 用户管理
 * 静态代理接口
 */
public interface UserManager {

   void findUser();
}

/**
 *用户管理实现类
 */
public class UserManagerImpl implements UserManager{
    @Override
    public void findUser() {
        System.out.println("*****UserManagerImpl实现类执行*******");
    }
}

/**
 * 静态代理类
 */
public class UserMangerProxy  implements UserManager{

    private UserManagerImpl userManager;
    public  UserMangerProxy(UserManagerImpl userManager){
        this.userManager=userManager;
    }

    @Override
    public void findUser() {
        System.out.println("-------执行前调-------------");
        userManager.findUser();
        System.out.println("-------执行后调-------------");
    }
    
    public static void main(String[] args) {
        UserManager userManager = new UserMangerProxy(new UserManagerImpl());
        userManager.findUser();
    }
}

2.Proxy动态代理

借助java内部的反射机制来实现的

2.1 Proxy举例
/**
 * 用户管理
 * 静态代理接口
 */
public interface UserManager {

   void findUser();
}
**
 *用户管理实现类
 */
public class UserManagerImpl implements UserManager {
    @Override
    public void findUser() {
        System.out.println("*****UserManagerImpl实现类执行*******");
    }
}
/**
 *动态代理类只能代理接口(不支持抽象类),
 * 代理类都需要实现InvocationHandler类,实现invoke方法。
 * 该invoke方法就是调用被代理接口的所有方法时需要调用的,该invoke方法返回的值是被代理接口的一个实现类
 */
public class UserMangerProxy  implements InvocationHandler {

    private Object targetObject;

    //绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
    public Object newProxyInstance(Object targetObject){
        this.targetObject=targetObject;
        //该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
        //第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
        //第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
        //第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法根据传入的目标返回一个代理对象
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(),this);
    }
    
    @Override
    //关联的这个实现类的方法被调用时将被执行
    /*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("start-->>");
        //打印方法名,参数值
        System.out.println("The runing method name is:"+method.getName());
        if(args!=null){
       		for(int i=0;i<args.length;i++){
            	System.out.println(args[i]);
        	}
        }
        Object ret=null;
        try{
            /*原对象方法调用前处理日志信息*/
            System.out.println("satrt-->>");

            //调用目标方法
            ret=method.invoke(targetObject, args);
            /*原对象方法调用后处理日志信息*/
            System.out.println("success-->>");
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("error-->>");
            throw e;
        }
        return ret;
    }

    public static void main(String[] args){
        UserMangerProxy logHandler=new UserMangerProxy();
        UserManager userManager=(UserManager)logHandler.newProxyInstance(new UserManagerImpl());
        userManager.findUser();
    }
}

Proxy.newProxyInstance(*,*,*) 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例,传入的三个参数

  • 第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
  • 第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
  • 第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法,根据传入的目标返回一个代理对象

3.CGLIB动态代理

Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。CGLIB具有简单易用,它的运行速度要远远快于JDK的Proxy动态代理:

cglib有两种可选方式,继承和引用。第一种是基于继承实现的动态代理,所以可以直接通过super调用target方法,但是这种方式在spring中是不支持的,因为这样的话,这个target对象就不能被spring所管理,所以cglib还是才用类似jdk的方式,通过持有target对象来达到拦截方法的效果。

CGLIB的核心类:

  • net.sf.cglib.proxy.Enhancer – 主要的增强类
  • net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户自定义实现
  • net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。
/**
 *用户管理实现类
 */
public class UserManagerImpl {
    public void findUser() {
        System.out.println("*****UserManagerImpl实现类执行*******");
    }
}

public class UserMangerProxy implements MethodInterceptor {

	/**
     * @param obj 代理对象
     * @param method 委托类方法
     * @param args  方法参数
     * @param proxy 代理方法的MethodProxy对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before:" + method);
        Object object = proxy.invokeSuper(obj, args);
        System.out.println("After:" + method);
        return object;
    }

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserManagerImpl.class);
        enhancer.setCallback(new UserMangerProxy());
        UserManagerImpl userMangerProxy = (UserManagerImpl)enhancer.create();
        userMangerProxy.findUser();
    }
}
代理方式实现优点缺点特点
静态代理代理类与委托类实现同一接口,并且在代理类中需要硬编码接口实现简单,容易理解代理类需要硬编码接口,在实际应用中可能会导致重复编码,浪费存储空间并且效率很低
JDK动态代理代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理不需要硬编码接口,代码复用率高只能够代理实现了接口的委托类底层使用反射机制进行方法的调用
CGLIB动态代理代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口不能对final类以及final方法进行代理底层将方法全部存入一个数组中,通过数组索引直接进行方法调用

反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)

文章参考地址:
https://blog.youkuaiyun.com/heyutao007/article/details/49738887

CGLIB动态代理反编译源码:
https://www.jianshu.com/p/13aa63e1ac95

import net.sf.cglib.core.Signature;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;

// 
// Decompiled by Procyon v0.5.30
// 

public class UserService$$EnhancerByCGLIB$$394dddeb extends UserService implements Factory
{
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static final Method CGLIB$add$0$Method;
    private static final MethodProxy CGLIB$add$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;

    
    static void CGLIB$STATICHOOK2() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        final Class<?> forName = Class.forName("UserService$$EnhancerByCGLIB$$394dddeb");
        final Class<?> forName3;
        CGLIB$add$0$Method = ReflectUtils.findMethods(new String[] { "add", "()V" }, (forName3 = Class.forName("UserService")).getDeclaredMethods())[0];
        CGLIB$add$0$Proxy = MethodProxy.create((Class)forName3, (Class)forName, "()V", "add", "CGLIB$add$0");
    }
    
    final void CGLIB$add$0() {
        super.add();
    }
    
    public final void add() {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            cglib$CALLBACK_2.intercept((Object)this, UserService$$EnhancerByCGLIB$$394dddeb.CGLIB$add$0$Method, UserService$$EnhancerByCGLIB$$394dddeb.CGLIB$emptyArgs, UserService$$EnhancerByCGLIB$$394dddeb.CGLIB$add$0$Proxy);
            return;
        }
        super.add();
    }
     
    static {
        CGLIB$STATICHOOK2();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值