代理模式:动态代理、静态代理
注意事项:
1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
静态代理:
静态代理类需要实现委托类实现的接口,实际业务处理由委托对象处理。
静态代理实现中,一个委托类对应一个代理类,代理类在编译期间就已经确定。
接口
public interface Subject {
public void doSomething();
}
委托类1:
public class FatherSubject implements Subject {
@Override
public void doSomething() {
System.out.println("Father do something ....");
}
}
委托类2:
public class SonSubject implements Subject {
@Override
public void doSomething() {
System.out.println("Son do something ....");
}
}
代理类:
public class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject ){
if (subject==null) {
throw new RuntimeException("委托对象不能为空");
}
this.subject=subject;
}
@Override
public void doSomething() {
//由实际委托对象处理
subject.doSomething();
}
}
测试类:
Subject subject=new ProxySubject(new FatherSubject());
subject.doSomething();
subject=new ProxySubject(new SonSubject());
subject.doSomething();
测试结果:
Father do something ....
Son do something ....
动态代理:
动态代理代理的对象不确定,代理类需要实现InvocationHandler,当执行handler.doSomething()时,会调用invoke方法。
动态代理类:
public class DynamicProxy implements InvocationHandler {
private Object target; //代理的委托对象
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
public Object getInstance(){
ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
return Proxy.newProxyInstance(classLoader, target.getClass().getInterfaces(), this);
}
}
测试:
Subject target = new FatherSubject();
DynamicProxy dynamicProxy=new DynamicProxy(target);
Subject handler=(Subject) dynamicProxy.getInstance();
handler.doSomething();
测试结果:
Father do something ....
使用Proxy、InvocationHandler、反射实现动态代理,代理的委托对象必须是接口的实现类的对象,当没有接口时就不适应。使用CGlib的MethodInterceptor课实现无接口的动态代理。
CGlib实现动态代理
public class CglibProxy implements MethodInterceptor{
/**
* 委托类Class.
*/
private Class<?> consignor;
public CglibProxy(Class<?> consignor){
this.consignor=consignor;
}
@Override
public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(obj, arg2);
}
public Object getInstance(){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(consignor);
enhancer.setCallback(this);
return enhancer.create(); //创建代理类
}
}
UserServiceImpl
public class UserServiceImpl {
public void add(){
System.out.println("UserServiceImpl add method invoked ...");
}
}
测试:
CglibProxy cglibProxy=new CglibProxy(UserServiceImpl.class);
UserServiceImpl userServiceImpl=(UserServiceImpl)cglibProxy.getInstance();
userServiceImpl.add();
测试结果:
UserServiceImpl add method invoked ...
jdk和cglib动态代理实现的区别
1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;