为其他对象提供一种代理以控制对这个对象的访问。
按照代理创建的时期来进行分类的话, 可以分为两种:静态代理、动态代理。静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了。动态代理是在程序运行时通过反射机制动态创建的。
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。
实现
这里假设Tom要买一套房子,然后自己没有足够的资金,于是就让他的父亲代理他来给他买下这套房子。
买房子接口:
public interface BuyHouse {
void Buy();
}
Tom类:
public class Tom implements BuyHouse {
public void Buy() {
System.out.println("Tom买到房子了...");
}
}
Father类:
public class Father implements BuyHouse {
private Tom tom;
public Father(Tom tom){
this.tom = tom;
}
public void Buy() {
System.out.println("Father给Tom买了房子...");
tom.Buy();
}
}
静态代理的优缺点:
动态代理
下面我们使用JDK动态代理的方式来对上面的静态代理示例进行改写
买房子接口和Tom类都和上面的一样
创建代理类JdkProxy:
public class JdkProxy implements InvocationHandler {
private Object target;
//接收被代理的目标对象对象
public JdkProxy(Object target){
this.target = target;
}
//生成目标对象的代理对象
public Object getProxyInstance(){
Object instance = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return instance;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始Jdk动态代理,来给Tom买房子");
//执行目标对象的方法
Object returnVal = method.invoke(target,args);
return returnVal;
}
}
测试类:
public class testJdkProxy {
@Test
public void test(){
BuyHouse tom = new Tom();
JdkProxy jdkProxy = new JdkProxy(tom);
BuyHouse proxyInstance = (BuyHouse)jdkProxy.getProxyInstance();
proxyInstance.Buy();
}
}
/**测试结果
开始Jdk动态代理,来给Tom买房子
Tom买到房子了...
*/
注意Proxy.newProxyInstance()方法接受三个参数:
静态代理和JDK代理模式都要求目标对象实现一个接口,但是有时候目标对象只是一个单独的对象,并没有实现任何对象,这个时候可以使用目标对象的子类来实现代理,这就是Cglib代理。
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
实现
创建没有实现接口的Tom类:
public class Tom {
public void Buy() {
System.out.println("Tom买到房子了...");
}
}
创建Cglib代理类:
public class CglibProxy implements MethodInterceptor {
private Object target;
public Object getProxyInstance(Object target){
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开始Cglib代理,来给Tom买房子");
Object returnVal = method.invoke(target, objects);
return returnVal;
}
}
创建测试类:
public class testCglibProxy {
@Test
public void test(){
Tom proxyInstance = (Tom) new CglibProxy().getProxyInstance(new Tom());
proxyInstance.Buy();
}
}
/**测试结果
开始Cglib代理,来给Tom买房子
Tom买到房子了...
*/
CGLIB代理总结: CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。
原文:https://www.cnblogs.com/lee0527/p/11884981.html