各种动态代理的区别
1、CglibAopProxy:在从容器中获取bean的时候,动态织入代码,动态构建字节码,采用ASM、javavssist组件修改,实现Cglib动态代理不需要接口去实现。
2、JdkDynamicAopProxy:动态构建字节码,采用ASM、javavssist组件修改,实现JDK动态代理需要接口去实现。
3、Aspectj:编译代码时,将目标代码的字节码织入代码,在Eclipse编译时就已经织入了,属于静态代理。
4、Instrumention:基于javaagent,类装载的时候动态拦截去修改。
动态代理原理
通过InvocationHandler接口,将代理对象、目标对象、代理逻辑连接一起。如下代码IUser属于代理对象,UserImpl属于目标对象,method.invoke(target, args);的前后属于代理逻辑。Proxy包含InvocationHandler,InvocationHandler包含目标对象,在执行目标对象时,动态织入代码逻辑,比如权限校验、日志记录。
一句话,目的就是生成一个UserImpl$Proxy,这个类的invoke包含了织入代码和调用目标对象的method.invoke方法
public class InvocationHandlerTest{
public static void main(String[] args) {
IUser user = (IUser)Proxy.newProxyInstance(InvocationHandlerTest.class.getClassLoader(), new Class[]{IUser.class}, new InvocationHandler(){
UserImpl target = new UserImpl();// 目标方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("相当于@AspectJ的@Before"); //代理逻辑
Object result = method.invoke(target, args);
System.out.println("相当于@AspectJ的@After");
return result;
}
});
int sayHelloResult = user.sayHello();
System.out.println("sayHelloResult="+sayHelloResult);
}
}
//代理对象
interface IUser{
int sayHello();
}
class UserImpl implements IUser{
@Override
public int sayHello() {
System.out.println("hello!");
return 0;
}
}
java动态代理是在构建代理对象(IUser)的过程中构建一个新的class(UserImpl),过程如下:
1、Proxy基于代理接口(IUser)获取目标对象(UserImpl)
(1)、从缓存中获取
(2)、缓存没有,时使用ProxyGenerator重新构建目标对象(UserImpl)class字节码,这个字节码extends Proxy implments IUser,invoke方法包含了InvocationHandler的invoke方法里的所有逻辑
(3)、调用本地方法装载目标对象class字节码
(4)、通过Class.forName返回重新构建后的class对象
2、使用反射生成代理对象UserImpl
3、通过method.invoke(target, args);调用代理对象
源码调用栈:
.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Class<?> cl = getProxyClass0(loader, intfs);
WeakCache.get(loader, interfaces);
// ProxyGenerator重新构建目标对象(UserImpl)class字节码,这个字节码extends Proxy implments IUser,invoke方法包含了InvocationHandler的invoke方法里的所有逻辑
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
// 调用本地方法装载目标对象class字节码
native Class<?> defineClass0(ClassLoader loader, String name, byte[] b, int off, int len)
Constructor<?> cons = cl.getConstructor(constructorParams);
cons.newInstance(new Object[]{h});
应用协议代理
思路:
1、重写HttpURLConnection
2、重写HttpStreamHandlerFactory
3、重写Handler