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");//执行新增方法
}
/**
* 设置保存Cglib代理生成的类文件。
*
* @throws Exception
*/
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待续。。。
参考文档: