动态代理proxy与CGLib

时间:2021-08-03 15:18:40

静态代理

定义一个接口
/** 
* 定义一个账户接口
*
* @author Administrator
*
*/

public interface Count {
// 查看账户方法
public void queryCount();

// 修改账户方法
public void updateCount();

}
接口实现类
public class CountImpl implements Count {  

@Override
public void queryCount() {
System.out.println("查看账户方法...");

}

@Override
public void updateCount() {
System.out.println("修改账户方法...");

}

}
接口实现代理类
/** 
* 这是一个代理类(增强CountImpl实现类)
*
* @author Administrator
*
*/

public class CountProxy implements Count {
private CountImpl countImpl;

/**
* 覆盖默认构造器
*
* @param countImpl
*/

public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
}

@Override
public void queryCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.queryCount();
System.out.println("事务处理之后");
}

@Override
public void updateCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.updateCount();
System.out.println("事务处理之后");

}

}
运行
public class CountTest {  

/**
* @param args
*/

public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();

}

}

从静态代理中可以看出:
1.接口:代理类需要实现一个接口,这个接口和委托类的接口是一样的,这样proxy才能和委托类行为表现一致
2. 方法(Method):由于接口限制,proxy类中也要有interface中的各个方法,这就造成了代码重复

JDK动态代理

接口
public interface Hello {

public void sayHello(String name);
}
接口实现
public class HelloImpl implements Hello {

public void sayHello(String name) {

System.out.println("Hello ,"+name);
}

}

代理类

public class JDKDyProxy implements InvocationHandler {

private Object target;

public JDKDyProxy(Object target) {
this.target = target;
}

@SuppressWarnings("unchecked")
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}


public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args);
after();
return result;
}

private void before(){
System.out.println("before");
}
private void after(){
System.out.println("after");
}

}

运行

public class Test1 {

public static void main(String[] args) {

Hello helloProxy = new HelloImpl();

JDKDyProxy jdkDyProxy = new JDKDyProxy(helloProxy);

Hello proxy = jdkDyProxy.getProxy();
proxy.sayHello("fsdafd");


}

}

JDK代理要有接口的类才可以,没的接口的类是不能代理的

CGLib动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

代理类
public class CGLibProxy implements MethodInterceptor{

private static final CGLibProxy instance = new CGLibProxy();

private CGLibProxy() {
}

public static CGLibProxy getInstance() {
return instance;
}

@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> cls){
return (T)Enhancer.create(cls, this);
}

public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
Object result =proxy.invokeSuper(obj, args);
after();
return result;
}

private void after() {
System.out.println("after");
}



private void before() {

System.out.println("before");

}
}

运行

    public static void main(String[] args) {

/*Hello helloProxy = new HelloImpl();

JDKDyProxy jdkDyProxy = new JDKDyProxy(helloProxy);

Hello proxy = jdkDyProxy.getProxy();
proxy.sayHello("fsdafd");*/
Hello proxy = CGLibProxy.getInstance().getProxy(HelloImpl.class);
proxy.sayHello("ppp");

}

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,
但是CGLib在创建代理对象时所花费的时间却比JDK多得多,
所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,
反之,使用JDK方式要更为合适一些。
同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。