Java中的代理
代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。
- 增加额外功能,进行增强
- 引入第三方代理类,进行解耦
- 静态代理
请参考下面的代码:
1 2 3 4 5 6 7
|
public interface StarService { void sing(); void jump(); }
|
1 2 3 4 5 6 7 8 9 10 11 12
|
public class StarServiceImpl implements StarService{ public void sing() { System.out.println(" sing a song "); }
public void jump() { System.out.println(" just dance "); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class StarServiceProxy implements StarService {
private StarService starService; public StarServiceProxy(StarService starService) { this.starService = starService; }
public void sing() { System.out.println("唱歌之前先联系综艺节目,确定时间、地点"); starService.sing(); System.out.println("表演结束之后,安排下一场演出"); }
public void jump() { return starService.jump(); System.out.println("跳舞之后,观众鼓掌"); } }
|
1 2 3 4 5 6 7 8 9
| public class ProxyTest {
public static void main(String[] args) { StarService starService = new StarServiceImpl(); StarServiceProxy proxy = new StarServiceProxy(starService); proxy.sing(); } }
|
1 2 3 4
| 输出: 唱歌之前先联系综艺节目,确定时间、地点 sing a song 表演结束之后,安排下一场演出
|
总结:
- 静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展;
- 不足: 静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的修改,增加维护成本。
- 动态代理
Java中的动态代理需要java.lang.reflect.InvocationHandler
接口和 java.lang.reflect.Proxy
类的支持 。**jdk
的动态代理是面向接口的,即jdk
的动态代理只能代理实现接口的类,不能代理抽象类或者没有实现接口的类。**
java.lang.reflect.InvocationHandler
接口的定义如下:
1 2 3 4 5 6 7 8
|
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
|
java.lang.reflect.Proxy
类的定义如下:
1 2 3 4 5 6 7
|
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
|
jdk
动态代理流程:
- 通过实现
InvocationHandler
接口创建自己的调用处理器;
- 通过为 Proxy 类指定
ClassLoader
对象和一组interface
来创建动态代理类;
- 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
- 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class YourHandler implements InvocationHandler { private Object targetObject; public ProxyHandler( Object proxied ) { this.proxied = proxied; } @Ovrride public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {
return method.invoke( proxy, args); } }
|
实际应用时代码如下:
1 2 3 4 5 6 7 8
| RealSubject real = new RealSubject();
Subject proxySubject = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class}, new YourHandler(real)); proxySubject.method( Object[] args);
|
Cglib
代理
Cglib代理补充了jdk中只面向接口进行代理的不足,Cglib代理支持基于对象代理,不用关心该对象是否实现了某个接口。 Cglib是一个java字节码的生成工具,它动态生成一个被代理类的子类,子类重写被代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
以上面的StarServiceImpl
为被代理对象,举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public class MyMethodInterceptor 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; } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Star.class); enhancer.setCallback(new MyMethodInterceptor()); StarServiceImpl starService = (StarServiceImpl) enhancer.create(); starService.sing(); }
|
1 2 3 4
| 输出结果如下: Before: sing sing a song After: sing
|