关于Java中的代理
静态代理
所谓静态代理,就是代理类是由程序员自己编写的,在编译期就确定好了的。
1 2 3 4 5 6 7 8 9 10 11
| public interface HelloSerivice { public void say(); }
public class HelloSeriviceImpl implements HelloSerivice{
@Override public void say() { System.out.println("hello world"); } }
|
上面定义了一个接口和实现类,这就是代理模式中的目标对象和目标对象的接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class HelloSeriviceProxy implements HelloSerivice{
private HelloSerivice target; public HelloSeriviceProxy(HelloSerivice target) { this.target = target; }
@Override public void say() { System.out.println("记录日志"); target.say(); System.out.println("清理数据"); } }
|
上面定义了一个代理对象,实现了目标对象的接口,扩展了say方法。
1 2 3 4 5 6 7 8 9 10
| public class Main { @Test public void testProxy(){ HelloSerivice target = new HelloSeriviceImpl(); HelloSeriviceProxy proxy = new HelloSeriviceProxy(target); proxy.say(); } }
|
上面为测试类,可以想象得出输出为 记录日志//hello world//清理数据
这就是一个简单的静态代理模式的实现,代理模式中所有角色(代理对象、目标对象、目标对象的接口)等都是在编译期就确定好的。
静态代理用途:
1.控制真实对象的访问权限:通过代理对象控制真实对象的使用权限。
2.避免创建大对象:通过使用一个代理小对象来代表一个真实的大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。
3.增强真实对象的功能:这个比较简单,通过代理可以在调用真实对象的方法的前后增加额外功能。
动态代理
静态代理存在一些局限性,比如使用静态代理模式需要程序员手写很多代码,这个过程是比较浪费时间和精力的。一旦需要代理的类中方法比较多,或者需要同时代理多个对象的时候,这无疑会增加很大的复杂度。
动态代理中的代理类并不要求在编译期就确定,而是可以在运行期动态生成,从而实现对目标对象的代理功能。
反射是动态代理的一种实现方式。
动态代理的几种实现方式
1、JDK动态代理:java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。
2、Cglib动态代理:Cglib (Code Generation Library )是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。
二者区别:
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
Cglib包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。
Cglib与动态代理最大的区别就是:
使用动态代理的对象必须实现一个或多个接口
使用cglib代理的对象则无需实现接口,达到代理类无侵入。
动态代理实现
1 2 3 4 5 6 7 8
| public class UserServiceImpl implements UserService {
@Override public void add() { System.out.println("--------------------add----------------------"); } }
|
使用jdk动态代理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
super(); this.target = target;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { PerformanceMonior.begin(target.getClass().getName()+"."+method.getName()); Object result = method.invoke(target, args); PerformanceMonior.end(); return result; }
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this); }
}
public static void main(String[] args) {
UserService service = new UserServiceImpl(); MyInvocationHandler handler = new MyInvocationHandler(service); UserService proxy = (UserService) handler.getProxy(); proxy.add(); }
|
cglib动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class CglibProxy implements MethodInterceptor{ private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz){ enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } 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; } }
public class DoCGLib { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); UserServiceImpl proxyImp = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class); proxyImp.add(); } }
|
AOP
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。
JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。