代理模式
代理模式是一种设计模式,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展。
1、静态代理
优点:
代理使客户端不需要知道实现类是什么,怎么做的,而客户端只需知道代理即可(解耦合),对于如上的客户端代码,newUserManagerImpl()可以应用工厂将它隐藏,如上只是举个例子而已。
缺点:
1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
2、JDK动态代理
底层实现过程:
通过实现 InvocationHandler 接口创建自己的调用处理器;
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
原理:
实现InvocationHandler 接口,调用Proxy类的静态方法newProxyInstance创建动态代理,通过反射的机制获取代理类,该类必须实现一个接口
调用Proxy类的静态方法newProxyInstance即可,该方法会返回代理类对象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
接收的三个参数依次为:
ClassLoader loader:指定当前目标对象使用类加载器,写法固定
Class<?>[] interfaces:目标对象实现的接口的类型,写法固定
InvocationHandler h:事件处理接口,需传入一个实现类,一般直接使用匿名内部类
调用:
UserServiceProcyFactory proxy = new UserServiceProcyFactory();
UserService user = (UserService) proxy.getProxy(UserServiceImpl.class);
package proxy.JDKProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class PracticeJDKProxyFactory implements InvocationHandler{
Object impl;
public <T> Object getProxy(Class<T> clz){
try {
//实例化对象
impl = clz.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//创建动态代理
Object proxy = Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("之前");
//反射执行方法
Object invoke = method.invoke(impl, args);=
System.out.println("之后");
return invoke;
}
}
3、cglib动态代理
原理:
cglib是一个java字节码的生成工具,方式是继承,它动态生成一个被代理类的子类,子类重写被代理的类,因此final标记的类,无法用CGLIB做动态代理。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法
调用:
1、实现MethodInterceptor接口生成方法拦截器:
public class HelloMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Before: " + method.getName()); Object object = methodProxy.invokeSuper(o, objects); System.out.println("After: " + method.getName()); return object; } }
2、生成代理类对象并打印在代理类对象调用方法之后的执行结果:
public class Client { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/zhanghao/Documents/toy/spring-framework-source-study/"); Enhancer enhancer = new Enhancer(); //继承被代理类 enhancer.setSuperclass(HelloServiceImpl.class); //设置回调 enhancer.setCallback(new HelloMethodInterceptor()); //设置代理类对象 HelloServiceImpl helloService = (HelloServiceImpl) enhancer.create(); //在调用代理类中方法时会被我们实现的方法拦截器进行拦截 helloService.sayBey(); } }
Enhancer是CGLIB的字节码增强器,可以很方便的对类进行拓展。
创建代理类的过程:
生成代理类的二进制字节码文件;
加载二进制字节码,生成Class对象;
通过反射机制获得实例构造,并创建代理类对象。
4、静态代理和动态代理的区别:
静态代理类:由程序员创建或由特定工具bai自动生成源代码,再对其编译。在du程序运行前,代理类的.class文件就已经存在了。
动态代理类:在程序运行时,运用反射机制动态创建而成。
评论