动态特性 ---动态代理
动态代理简介:
动态代理是一种强大的功能,它可以在运行时动态创建一个类,实现一个或者多个接口,可以在不修改原来的类的基础上动态的添加方法,修改行为。
静态代理:
代理是java 设计模式中的一种,基础概念和日常生活中的概念类似。代理背后一般至少有一个实际对象,代理的外部功能和实际对象一般是一样的,用户和代理打交道,不直接接触实际对象,虽然外部公共和实际对象一样,但代理有它存在的价值。比如:
(1) 节省成本比较高的实际对象的创建开销,按需延迟加载,创建代理时并不真正创建实际对象,而只是保存实际对象的地址,在需要时再加载或创建。
(2) 执行权限检查,代理检查权限后,在调用实际对象。
(3) 屏蔽网络差异和复杂性,代理在本地,而实际对象在其它服务器上,调用本地代理时,请求其它服务器。
静态代理示例:
package Proxy;
/**
* 静态代理
*/
public class StaticProxy {
interface Iservice {
void sayHello();
}
static class RealService implements Iservice {
@Override
public void sayHello() {
System.out.println("I'm RealService!");
}
}
static class ProxyService implements Iservice {
private RealService realService;
public ProxyService(RealService realService) {
this.realService = realService;
}
@Override
public void sayHello() {
realService.sayHello();
System.out.println("I'm ProxyService!");
}
}
public static void main(String[] args) {
RealService realService = new RealService();
ProxyService proxyService = new ProxyService(realService);
proxyService.sayHello();
}
}
java sdk动态代理:
在静态代理中,代理类是直接定义在代码中的,在动态代理中,代理类是动态生成的。
示例:
package Proxy;
import java.lang.reflect.*;
/**
* 动态代理demo
*/
public class SimpleJDKDynamicsDemo {
interface Iservice {
public void sayHello();
}
static class RealService implements Iservice {
@Override
public void sayHello() {
System.out.println("I'm RealService say Hello!");
}
}
static class SimpleInvocationHandler implements InvocationHandler {
//被代理对象
private Object object;
//给被代理对象赋值
public SimpleInvocationHandler(Object object) {
this.object = object;
}
/**
*
* @param proxy 代表代理对象本身,不是被代理的对象,这个参数一般用处不大
* @param method 表示正在调用的方法
* @param args 表示方法的参数
* @return
* @throws Throwable
* 不能将传进来的proxy作为参数使用到menthod 的invoke()方法中做参数,因为proxy表示当前代理对象,用
* proxy 当参数又会直接调用到SimpleInvocationHandler 的invoke 方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用的方法是: "+method.getName());
Object result = method.invoke(object,args);
System.out.println("结束时调用的方法:"+method.getName());
return result;
}
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Iservice realService1 = new RealService();
//newProxyInstance(ClassLoader loader,Class<?> [] interfaces,InvocationHandler h)
//.loader 表示类加载器
//.interfaces 表示代理类要实现的接口列表,是一个数组,元素的类型只能是接口,不能是普通的类
//.h的类型为InvocationHandler,它是一个接口,也定义在java.lang.reflect包中,它之定义了一个方法invoke,对
//代理接口的所有方法的调用都会转给该方法
//newProxyInstance()的返回值是Object,可以强制转换为intefaces 里的某个接口类型,但它不能强制转为
//某个类类型,即使是它的实际代理的对象类型,因为子类可以装一下父类还可以转换回去,
// 但是父类却不能装为子类,并不知道子类的那些东西
Iservice proxyIservice = (Iservice) Proxy.newProxyInstance(
Iservice.class.getClassLoader(),
new Class[]{Iservice.class},
new SimpleInvocationHandler(realService1));
proxyIservice.sayHello();
//动态代理的基本原理
Iservice realService = new RealService();
//创建代理类定义,定义会被缓存
Class<?> proxyCls = Proxy.getProxyClass(Iservice.class.getClassLoader(),Iservice.class);
//获取代理类的构造方法,构造方法有一个InvocationHandler对象
Constructor<?> ctor = proxyCls.getConstructor(InvocationHandler.class);
//创建InvocationHandler对象,创建代理类对象
InvocationHandler handler = new SimpleInvocationHandler(realService);
//$Proxy0 是代理类的 类定义
Iservice proxyService = (Iservice) ctor.newInstance(handler);
proxyService.sayHello();
}
}
动态代理的基本原理分为三步:
(1)通过Proxy.getProxyClass() 创建代理类定义,类定义会被缓存。
(2)通过反射,获取到代理类的构造方法,构造方法 有一个InvocationHander类型的参数。
(3) 创建自定义Hander 继承InvocationHander 接口,实现自定义的代理逻辑,最后创建代理类。
生成的代理类如下:
package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* java SDK动态生成的代理类示例
*$Proxy0 的父类是proxy,proxy类定义了一个InvocationHandler类型的参数,
*$Proxy0 的构造方式是为了保存InvocationHandler,
* $Proxy0 同样也实现了Iservice接口,当$Proxy0 调用sayHello方法时,会转发给InvocationHandler的实现类取去处理
*/
final class $Proxy0 extends Proxy implements SimpleJDKDynamicsDemo.Iservice {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler h) {
super(h);
}
public final void sayHello() {
this.h.invoke(this,m3,null);
}
public final int hashCode() {
return ((Integer) this.h.invoke(this,m0,null)).intValue();
}
public final boolean equals(Object obj) {
return ((Boolean) this.h.invoke(this,m1,new Object[]{obj})).booleanValue();
}
public final String toString() {
return (String) this.h.invoke(this,m2,null);
}
static{
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[]{Class.forName("java.lang.Object")});
m3 = Class.forName("Proxy.SimpleJDKDynamicsDemo$Iservice")
.getMethod("sayHello",new Class[0]);
m2 =Class.forName("java.lang.Object").getMethod("toString");
m0 =Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
通用的动态代理类示例:
package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 通用动态代理实例
*
* 共享同一个代理逻辑SimpleInvocationHandler,去获取代理对象执行方法
*/
public class CommonProxyDemo {
interface IserviceA {
void sayHello();
}
interface IServiceB {
void fly();
}
static class ServiceAImpl implements IserviceA {
@Override
public void sayHello() {
System.out.println("IserviceA say Hello!");
}
}
static class ServiceBImpl implements IServiceB {
@Override
public void fly() {
System.out.println("IserviceB say fly!");
}
}
static class SimpleInvocationHandler implements InvocationHandler {
private Object object;
public SimpleInvocationHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("entering" + object.getClass().getSimpleName() + "::"+ method.getName());
Object result = method.invoke(object,args);
System.out.println("leaving" + object.getClass().getSimpleName() + "::" + method.getName());
return result;
}
}
public static <T> T getProxy(Class<?> cls,T obj){
return (T) Proxy.newProxyInstance(cls.getClassLoader(),
new Class[]{cls},new SimpleInvocationHandler(obj));
}
public static void main(String[] args) {
IserviceA a = new ServiceAImpl();
IserviceA aProxy = getProxy(IserviceA.class,a);
aProxy.sayHello();
IServiceB b = new ServiceBImpl();
IServiceB bProxy = getProxy(IServiceB.class,b);
bProxy.fly();
}
}
CGLIB 动态代理:
Java sdk 动态代理的局限在于,它只能代理为接口创建对象。返回的代理对象也只能是转换到某个接口类型。如果一个类没有接口,或者希望代理非接口中定义的方法,那就没办法了。但有一个地方法类库cglib,可以做到这一点.它通过继承这个类,重写这个类的方法。
示例:
package Proxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
*java sdk 动态代理的局限是只能为接口创建代理,返回的代理对象也只能转换为接口类型
* 要实现不是接口的代理需要用到第三方的类库,cglib,它是通过继承实现的,它也是动态创建一个类,
* 但这个类的父类是被代理的类,代理类重写父类的所有public非final方法,改为调用Callback中的相关方法
*/
public class SimpleCGLBDynamicsDemo {
static class RealSerice {
public void sayHello(){
System.out.println("RealService say hello !!");
}
}
static class SimpleInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("entering" + method.getName());
Object result = methodProxy.invokeSuper(o,args);
System.out.println("leaving" + method.getName());
return result;
}
}
private static <T> T getProxy(Class<T> cls){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
public static void main(String[] args) {
RealSerice realSericeProxy = getProxy(RealSerice.class);
realSericeProxy.sayHello();
}
}
总结:
动态代理广泛的应用于各种系统程序,框架/库。用于为应用程序提供易用的支持,实现Aop,以及其它灵活的通用功能。理解了动态代理,我们就能更好的利用这些系统程序、框架、库,在需要的时候也可以自己创建动态代理。