静态代理
静态代理是代理模式的实现方式之一,是相对于动态代理而言的。所谓静态代理是指,在程序运行前,由程序员创建或特定工具自动生成源代码并对其编译生成.class文件。
静态代理的实现只需要三步:首先,定义业务接口;其次,实现业务接口;然后,定义代理类并实现业务接口;最后便可通过客户端进行调用。
/**
* 代理接口
*/
public interface DemoService {
public void print(String param);
}
/**
* 真正的实现类
*/
public class DemoServiceImpl implements DemoService {
@Override
public void print(String param) {
System.out.println("real method:" + param);
}
}
/**
* 代理类
*/
public class DemoProxy implements DemoService {
private DemoService demoService;
public DemoProxy(DemoServiceImpl impl) {
this.demoService = impl;
}
@Override
public void print(String param) {
System.out.println("before real method");
demoService.print("AAA");
System.out.println("after real method");
}
}
//测试类
public class Test {
public static void main(String[] args) {
DemoService demoService = new DemoProxy(new DemoServiceImpl());
demoService.print("AAA");
}
}
静态代理的局限性:
一个代理类Proxy只能服务Subject一种接口,如果有10个不同类型的对象,需要创建10个代理类,类的数量激增、也增加了代码的冗余
如果只用一个代理类,就能完成全部的代理功能就好了,于是就有了动态代理
动态代理
和静态代理不同,动态代理的字节码是在程序运行期间,由JVM根据反射等机制动态生成的。代理类和实际类的关系是在程序运行时确定的,依托反射等机制,动态代理可以动态生成任意类型的代理类,一个代理的处理程序就可以处理多种对象。
java中的动态代理有两种,一种是java自带的jdk动态代理,一种是基于cglib的动态代理
JDK动态代理
(1)Proxy 类提供了用于创建动态代理类和实例对象的方法,它是所创建的动态代理类的父类
(2)InvocationHandler 接口是代理处理程序类的实现接口,每一个被生成的代理类实例都可以提供一个相关的代理处理程序类,代理类实例的方法被调用时会回调invoke()方法
public interface DemoService {
public String print(String param);
}
public class DemoServiceImpl implements DemoService {
@Override
public String print(String param) {
System.out.println("REAL Method");
return param + " REAL METHOD";
}
}
public class ProxyHandler implements InvocationHandler {
private Object obj;
public ProxyHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before Real Method");
String print = (String)method.invoke(obj, args);
System.out.println("after Real Method");
return print;
}
}
public class Test {
public static void main(String[] args) {
DemoServiceImpl impl = new DemoServiceImpl();
ProxyHandler handler = new ProxyHandler(impl);
DemoService demo = (DemoService) Proxy.newProxyInstance(impl.getClass().getClassLoader(),
impl.getClass().getInterfaces(), handler);
demo.print("AAAA");
}
}
JDK动态代理的局限性:如果是抽象类或者一般的类需要进行代理,jdk动态代理就无法满足了,只有使用cglib动态代理
cglib动态代理
主要用到import net.sf.cglib.proxy包下的MethodInterceptor、MethodProxy和Enhancer类
(1)、MethodInterceptor
MethodInterceptor类是方法拦截器,代理类实例的方法被调用时会回调MethodInterceptor的intercept()方法拦截,用来实现自己的代理逻辑,类似于jdk动态代理的InvocationHandler接口
(2)、MethodProxy
MethodProxy是intercept()方法中的第四个参数的类型,它是实际类方法的代理引用,使用methodProxy比使用jdk自身的method在效率上会有提升
(3)、Enhancer
Enhancer用来动态创建实际类子类的代理类实例,setSuperclass()方法设置实际类为父类,setCallback()方法建立方法回调,create()方法创建一个代理类实例
public class RealDemo {
public void print(String param) {
System.out.println("REAL METHOD " + param);
}
}
public Object newInstance(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method mrthod, Object[] arg2, MethodProxy proxy) throws Throwable {
System.out.println("BEFORE......");
Object object = proxy.invokeSuper(arg0, arg2);
System.out.println("AFTER......");
return object;
}
}
public class Test {
public static void main(String[] args) {
RealDemo demo = new RealDemo();
ProxyIntercept intercept = new ProxyIntercept();
RealDemo proxyDemo = (RealDemo) intercept.newInstance(demo);
proxyDemo.print("AAA");
}
}
jdk动态代理是由java内部的反射机制生成一个实现代理接口的匿名类,被代理的类必须要实现一个接口,如果某个类没有实现接口则不能生成代理对象,实际使用中会有一些局限性
cglib动态代理底层是借助asm来实现的,加载实际类的.class文件,修改其字节码生成子类来处理,比java反射效率要高一些,不过生成子类的方式也带来小问题:目标类不能声明成final,因为final类不能被继承,无法生成代理;目标方法也不能声明成final,final方法不能被重写,无法得到处理
参考:https://blog.csdn.net/justloveyou_/article/details/79407248
https://www.cnblogs.com/ctxsdhy/p/5815492.html