动态代理对比

动态代理对比,第1张

动态代理对比

JDK和CGlib对比图:

 

代码实现--准备接口和实现类

public interface UserManager {
	//新增用户抽象方法
    void addUser(String userName,String password);
    //删除用户抽象方法
    void delUser(String userName);
}

public class UserManagerImpl implements UserManager {
    @Override
    public void addUser(String userName, String password) {
        System.out.println("调用了新增的方法!");
        delUser(userName);
    }
    @Override
    public void delUser(String userName) {
        System.out.println("调用了删除的方法!");
    }
}

JDK动态代理:

public class JdkProxy implements InvocationHandler{

	private Object target;//需要代理的目标对象
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("JDK动态代理,监听开始!");
        Object result = method.invoke(target, args);
        System.out.println("JDK动态代理,监听结束!");
        return result;
	}
    //定义获取代理对象方法
    private Object getJdkProxy(Object targetObject) {
        this.target = targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }
    public static void main(String[] args) {
    	System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");//生成字节码文件
    	JdkProxy jdkProxy = new JdkProxy();//实例化JDKProxy对象
    	UserManager user = (UserManager) jdkProxy.getJdkProxy(new UserManagerImpl());//获取代理对象
    	System.out.println(user.getClass());
        user.addUser("tester", "root");
	}
}

运行效果:

此时生成的proxy.class---only one:

 

它的代理为每一个方法生成对应的实现,并通过调用h也就是InvocationHandler实例变量的invoke的方法去调用,调用的时候只是传入的方法和参数不同而已。在invoke方法里面,通过反射调用,此时target不是代理类,是本类,相当于直接用本类的实例调用方法,不走代理增强。 

方法都在Proxy.class中进行了载入:

代码实现--CGLIB---proxy.invokeSuper

public class CglibProxy implements MethodInterceptor{
	
	 private Object target;//需要代理的目标对象
	

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("Cglib动态代理,监听开始!");
		proxy.invokeSuper(obj, args);
		System.out.println("Cglib动态代理,监听结束!");
        return obj;
//      Object invoke = method.invoke(target, args);//方法执行,参数:target 目标对象 args参数数组
//        System.out.println("Cglib动态代理,监听结束!");
//        return invoke;
	}
	//定义获取代理对象方法
    public Object getCglibProxy(Object objectTarget){
        //为目标对象target赋值
        this.target = objectTarget;
        Enhancer enhancer = new Enhancer();
        //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类
        enhancer.setSuperclass(objectTarget.getClass());
        enhancer.setCallback(this);// 设置回调
        Object result = enhancer.create();//创建并返回代理对象
        return result;
    }

    public static void main(String[] args) throws Exception {
    	System.out.println(System.getProperty("user.dir"));
    	saveGeneratedCGlibProxyFiles(System.getProperty("user.dir"));
        CglibProxy cglib = new CglibProxy();//实例化CglibProxy对象
        UserManager user =  (UserManager) cglib.getCglibProxy(new UserManagerImpl());//获取代理对象
        user.addUser("admin", "123123");//执行新增方法
    }
    
    
    public static void saveGeneratedCGlibProxyFiles(String dir) throws Exception {
        Field field = System.class.getDeclaredField("props");
        field.setAccessible(true);
        Properties props = (Properties) field.get(null);
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, dir);//dir为保存文件路径
        props.put("net.sf.cglib.core.DebuggingClassWriter.traceEnabled", "true");
    }

}

运行结果:

此时生成的cglib.class文件---多个

 

 

CGLIB依赖ASM的字节码生成库,允许在运行时对字节码进行修改和动态生成。他对所有的方法都进行了增强,每次执行到一个方法 都会从已经增强后的字节码里面查找,找到后执行该方法。当在本类中调用其他方法的时候,其他方法也是增强的。 

修改CGLIB增强部分的代码:

@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("Cglib动态代理,监听开始!");
//		proxy.invokeSuper(obj, args);
//		System.out.println("Cglib动态代理,监听结束!");
//        return obj;
      Object invoke = method.invoke(target, args);//方法执行,参数:target 目标对象 args参数数组
        System.out.println("Cglib动态代理,监听结束!");
        return invoke;
	}

 此时的cglib.class文件 

Confused?

For invokeSuper,当调用到addUser的时候,此时是一个增强类。好像说的是废话。 

 而且当我们断点到delUser的时候,发现delUser也进入到了MethodInterceptor的intercept方法,delUser也被增强啦。but the reason is invokeSuper; the parameter passed in invokeSuper is a subclass of Cglib proxy, which is equivalent to calling the b() method of this subclass of Target$$EnhanceredByCGLIB, and it will definitely enter the callback again;

 但是通过method.invoke传的target不是增强的类。

同样通过下面的方式 传递的target也不是增强的类

public class CglibProxy implements MethodInterceptor{
	
	 private Object target;//需要代理的目标对象
	
	 public CglibProxy(Object target) {
	        super();
	        this.target = target;
	    }
	 
	 
	 
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("Cglib动态代理,监听开始!");
		Object res = proxy.invoke(target, args);
		System.out.println("Cglib动态代理,监听结束!");
        return res;
	}
	
    public static void main(String[] args) throws Exception {
 
        UserManagerImpl target = new UserManagerImpl();
        Enhancer e = new Enhancer();
        e.setSuperclass(UserManagerImpl.class);
        e.setCallback(new CglibProxy(target));
        UserManager t=(UserManager) e.create();
        t.addUser("tester", "123");
    }
    
    

也就是说调用 invokeSuper方法的时候传递的是一个增强的类,之后调用的方法都会进行增强。而invoke里面传递的是非增强类,之后调用本类的方法也不会被增强。

关于spring里面的cglib待续。。。

 

参考文档:

https://zhuanlan.zhihu.com/p/206628333 

https://www.programmerall.com/article/5507539399/

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5685643.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存