代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
为 了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访 问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。
Java 动态代理。具体有如下四步骤:
1、通过实现 InvocationHandler 接口创建自己的调用处理器;
InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发, 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler = new InvocationHandlerImpl(..);
2、通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象 代理类对象
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, … });
3、通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过反射从生成的代理类对象中获得构造函数对象
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });
4、通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
通过构造函数对象创建动态代理类实例
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });
实际使用过程更加简单,因为 Proxy 的静态方法 newProxyInstance 已经为我们封装了步骤 2 到步骤 4 的过程,所以简化后的过程如下:
InvocationHandler handler = new InvocationHandlerImpl(..);
// 通过 Proxy 直接创建动态代理类实例
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,
new Class[] { Interface.class },
handler );
注意:
1、Proxy 类是代理类的父类,这个规则适用于所有由 Proxy 创建的动态代理类。而且代理类类还实现了其所代理的一组接口,这就是为什么它能够被安全地类型转换到其所代理的某接口的根本原因。
2、委托类。首先,要注意不能有重复的接口,以避免动态代理类代码生成时的编译错误。其次,这些接口对于类装载器必须可见,否则类装载器将无 法链接它们,将会导致类定义失败。再次,需被代理的所有非 public 的接口必须在同一个包中,否则代理类生成也会失败。最后,接口的数目不能超过 65535,这是 JVM 设定的限制。
demo:
接口:
public interface PersonService {
public void eat(String foodName);
public void drink(String drinkName);
}
实现类:
public class PersonServiceImpl implements PersonService{
@Override
public void eat(String foodName) {
System.out.println(“eat…..” + foodName);
drink(“可乐”);
}
//看看在这个方法 执行的时候 能否执行代理类里面想要的代码?
//没能够执行,原因:因为执行eat(String foodName)的时候 已经不是代理类啦
@Override
public void drink(String drinkName) {
System.out.println(“drink….” + drinkName);
}
}
jdk动态代理
public class JdkProxyOne {
private Object targetObject;//代理目标
public Object createProxyInstance(Object obj){
this.targetObject = obj;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), new TargetHandelr());//代理类实例
}
class TargetHandelr implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("找饭店。。。");
Object invoke = method.invoke(targetObject, args);//回掉委托类的方法
System.out.println("吃完付钱");
System.out.println(proxy.getClass());//class com.sun.proxy.$Proxy0
return invoke;
}
}
}
测试:
public class TestJdkProxy {
public static void main(String[] args) {
JdkProxyOne jdkProxy = new JdkProxyOne();
PersonService personService = (PersonService) jdkProxy.createProxyInstance(new PersonServiceImpl());
InvocationHandler invocationHandler = Proxy.getInvocationHandler(personService);
System.out.println(invocationHandler.getClass());//获得代理类实例的调用处理器对象 class com.example.proxy.one.JdkProxyOne$TargetHandelr
personService.eat(“拉面”);//代理类执行方法 在不改变委托类的代码的情况下 添加要执行的代码
System.out.println(Proxy.isProxyClass(personService.getClass()));//true
}
}
jdk动态代理 对接口进行代理 对于非接口的 可以考虑cglib
他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
//一个需要被代理的类【委托类】,也就是父类,通过字节码技术创建这个类的子类,实现动态代理
public class AnimalService {
public void run(){
System.out.println(“dog is running”);
}
}
cglib获取代理类
///实现MethodInterceptor接口方法
public class CglibProxy implements MethodInterceptor{
private Object targetObject;
public Object createProxyInstance(Object target){
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass());//设置需要创建子类的类
enhancer.setCallback(this);
enhancer.setClassLoader(targetObject.getClass().getClassLoader());
return enhancer.create();////通过字节码技术动态创建子类实例
}
//intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,
//method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类实例。
//proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println(“前置代理”);
//通过代理类调用父类中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println(“后置代理”);
return result;
}
private void doBefore() {
System.out.println("before method invoke");
}
private void doAfter() {
System.out.println("after method invoke");
}
}
测试:
public static void main(String[] args) {
AnimalService animalService = new AnimalService();
CglibProxy cglibProxy = new CglibProxy();
AnimalService proxyAnimalService = (AnimalService) cglibProxy.createProxyInstance(animalService);
proxyAnimalService.run();
}
打印:
前置代理
dog is running
后置代理