静态代理
1、编写需要目标对象实现的接口
/**
* 接口
*/
public interface Action {
/**
* dosomething
*/
void doSomething();
}
2、编写目标类,实现接口
/**
* @author earthchen
* @date 2018/8/10
**/
public class RealObject implements Action {
@Override
public void doSomething() {
System.out.println(this.getClass().getName()+"dosomething....");
}
}
3、编写静态代理类,也需要实现该接口
/**
* 代理类
*
* @author earthchen
* @date 2018/8/10
**/
public class Proxy implements Action {
private Action realObject;
public Proxy(Action realObject) {
this.realObject = realObject;
}
@Override
public void doSomething() {
System.out.println("proxy do");
realObject.doSomething();
}
}
需要维护一个接口的对象
4、编写main方法进行测试
public class Main {
public static void main(String[] args) {
Action action = new RealObject();
Proxy proxy = new Proxy(action);
proxy.doSomething();
}
}
优缺点
这种代理方式需要代理对象和目标对象实现一样的接口。
优点:可以在不修改目标对象的前提下扩展目标对象的功能。
缺点:
- 冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。
- 不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。
jdk动态代理
1、和静态代理一样,编写一个接口
/**
* @author earthchen
* @date 2018/8/10
**/
public interface Action {
void doSomeThing();
}
2、编写多个目标类,实现接口
/**
* @author earthchen
* @date 2018/8/10
**/
public class RealObject1 implements Action {
@Override
public void doSomeThing() {
System.out.println(this.getClass().getName()+"do someThing...");
}
}
/**
* @author earthchen
* @date 2018/8/10
**/
public class RealObject2 implements Action {
@Override
public void doSomeThing() {
System.out.println(this.getClass().getName()+"do someThing...");
}
}
3、编写动态代理类,
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author earthchen
* @date 2018/8/10
**/
public class DynamicProxyHandler implements InvocationHandler {
private Action testAction;
public DynamicProxyHandler(Action testAction) {
this.testAction = testAction;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//代理扩展逻辑
System.out.println("proxy do");
return method.invoke(testAction, args);
}
}
4、编写main方法进行测试
public class Main {
public static void main(String[] args) {
RealObject1 realObject1 = new RealObject1();
Action proxy1 = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Action.class}, new DynamicProxyHandler(realObject1));
proxy1.doSomeThing();
RealObject2 realObject2 = new RealObject2();
Action proxy2 = (Action) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{Action.class}, new DynamicProxyHandler(realObject2));
proxy2.doSomeThing();
}
}
静态代理与动态代理的区别
- 静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
- 动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
特点:
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。
cglib代理
1、在pom.xml中引入cglib的依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
2、直接编写需要代理的目标类
public class RealObject {
public void doSomeThing(){
System.out.println(this.getClass().getName()+"do someThing...");
}
}
3、编写cglib代理类
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* @author earthchen
* @date 2018/8/10
**/
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object object) {
this.target = object;
}
/**
* 为目标对象生成代理对象
*
* @return
*/
public Object getProxyInstance() {
//工具类
Enhancer en = new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(this);
//创建子类对象代理
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before do someThing.....");
// 执行目标对象的方法
Object returnValue = method.invoke(target, objects);
System.out.println("after do someThing....");
return returnValue;
}
}
cglib与动态代理的区别
- 使用动态代理的对象必须实现一个或多个接口
- 使用cglib代理的对象则无需实现接口,达到代理类无侵入。
cglib特点
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。
如果想代理没有实现接口的类,就可以使用CGLIB实现CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)
- CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉
总结
- 静态代理实现较简单,只要代理对象对目标对象进行包装,即可实现增强功能,但静态代理只能为一个目标对象服务,如果目标对象过多,则会产生很多代理类。
- JDK动态代理需要目标对象实现业务接口,代理类只需实现InvocationHandler接口。
- 静态代理在编译时产生class字节码文件,可以直接使用,效率高。
- 动态代理必须实现InvocationHandler接口,通过反射代理方法,比较消耗系统性能,但可以减少代理类的数量,使用更灵活。
- cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。