代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,
代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供
特定的服务。
有了解动态代理你必须先了解java的反射机制(点击查看)
1. JDK动态代理(委托类必须接口实现,代理类实现InvocationHandler接口,springAop默认的实现方式)
2. Cglib动态代理(委托类可以不实现接口,也可以实现接口,代理类实现MethodInterceptor,spring的bean在没实现接口时使用的Cglib实现AOP),使用Cglib提供的过滤器CallbackFilter 可以明确表明,被代理的类(InfoManager)中不同的方法,被哪个拦截器(interceptor,即代理类)拦截。
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
//接口
public interface Count { public void CountAll(); public void AddMethod(); }
public class CountImpl implements Count{ @Override public void CountAll() { try{ Thread.sleep(2000); System.out.println("count start..."); }catch(Exception e){ e.printStackTrace(); } } @Override public void AddMethod() { System.out.println("AddMethod start..."); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class JDKProxy implements InvocationHandler{ private Count count; public JDKProxy(Count count){ this.count = count; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("begin..."); method.invoke(count, args); System.out.println("end..."); return null; } }
import java.lang.reflect.Proxy; public class CountFactory { public static Count getProxyInstance(Count count){ return (Count)Proxy.newProxyInstance(count.getClass().getClassLoader(), count.getClass().getInterfaces(), new JDKProxy(count)); } }
public class Client { public static void main(String[] arg){ Count count = new CountImpl(); Count countProxy = CountFactory.getProxyInstance(count); countProxy.CountAll(); count.CountAll(); } }
cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
cglib封装了asm,可以在运行期动态生成新的class。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。最流行的OR Mapping工具hibernate也使用CGLIB来代理单端single-ended(多对一和一对一)关联(对集合的延迟抓取,是采用其他机制实现的)
@代码:
//委托类
public class InfoManager { public void query() { System.out.println("query"); } public void delete() { System.out.println("delete"); } }//代理类 实现 MethodInterceptor
public class AuthProxy implements MethodInterceptor{ String name; public AuthProxy(String name){ this.name = name; } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { if(this.name.equals("dxswzj")){//当dxswzj时才可以操作 //对方法进行过滤 if(arg1.getName().equals("delete")){ System.out.println("you can't do delete!"); }else{ System.out.println("方法前置代理"); arg3.invokeSuper(arg0, arg2); System.out.println("方法后置代理"); } }else{ System.out.println("you can't do anything!"); } return null; } }
public class InfoManagerFactory { public static InfoManager getInstance(AuthProxy proxy){ Enhancer enhancer = new Enhancer(); //设置需要创建子类的类 enhancer.setSuperclass(InfoManager.class); enhancer.setCallback(proxy); //通过字节码技术动态创建子类实例 return (InfoManager)enhancer.create(); } }
public static void main(String[] arg){ Client c = new Client(); AuthProxy proxy = new AuthProxy("dxswzj"); InfoManager manager = InfoManagerFactory.getInstance(proxy); manager.delete(); manager.query(); }