java 为什么要用代理?java中为什么要给类使用代理它有哪些好处
大家好,关于java 为什么要用代理很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于java中为什么要给类使用代理它有哪些好处的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
java中为什么要给类使用代理它有哪些好处
代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色有:
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
java的动态代理为什么要用接口
其实java的规范就是根据JDK来规范的。java也必须在虚拟机来运行。至于java的动态代理可以不使用JDK的接口,而可以用spring的AOP动态代理。!
如果又什么疑问可以到我空间去看!
http://hi.baidu.com/2512149/blog/item/83fa889431716c027af48077.html
1.其实spring中的AOP的动态代理就是默认JDK中的动态代理机制来实现。
(思想:我们要把横切(散布)的东西给拿出来,成一个模块)
2.AOP应该是一个OOP的技术上一个补充!
接下来我们下一个动态代理,通过代码我们来了解下!
1.首先呢,我们上节讲的static代理的代理类将不会存在了我们将在运行期
生成。
2.我们建一个类动态安全检查(SecurityHandler)然后实现接口:InvocationHandler
3.声明目标对象,进行代理。
4.然后提供一个方法,返回代理对象。
5.我们把横切的问题全部给模块化了,都放在一个类里面!
6.在调Object newProxy()方法之前,它会先默认调用Object invoke()方法
所以我们把安全性检查方法放在里面就行了.跟着它会继续调用目标对象的真实调用。
*目标实现对象有返回值的有没有返回值的所以我们这里要注意。
*
Java代理的作用和实现
JDK动态代理
动态代理的核心其实就是代理对象的生成,即 Proxy.newProxyInstance(classLoader, proxyInterface, handler)。
让我们进入newProxyInstance方法观摩下,核心代码其实就三行。
这个方法需要三个参数:
ClassLoader,用于加载代理类的 Loader类,通常这个 Loader和被代理的类是同一个 Loader类。
Interfaces,是要被代理的那些那些接口。
InvocationHandler,就是用于执行除了被代理接口中方法之外的用户自定义的操作,也是用户需要代理的最终目的。用户调用目标方法都被代理到 InvocationHandler类中定义的唯一方法 invoke中。
//获取代理类 Class cl= getProxyClass(loader, interfaces);//获取带有InvocationHandler参数的构造方法 Constructor cons= cl.getConstructor(constructorParams);
//把handler传入构造方法生成实例 return(Object) cons.newInstance(new Object[]{ h});
一个典型的动态代理创建对象过程可分为以下四个步骤:
1、通过实现InvocationHandler接口创建调用处理器
IvocationHandler handler= new InvocationHandlerImpl(...);2、通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
Class clazz= Proxy.getProxyClass(classLoader,new Class[]{...});3、通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor constructor= clazz.getConstructor(new Class[]{InvocationHandler.class});4、通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy=(Interface)constructor.newInstance(new Object[](handler));为了简化对象创建过程,Proxy类中的newProxyInstance方法封装了2~4,只需两步即可完成代理对象的创建。
Subject proxySubject=(Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),new Class[]{Subject.class}, new InvocationHandlerImpl(real));
生成的proxySubject继承Proxy类实现Subject接口。实现的Subject的方法实际是调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的方法(Object result=method.invoke(proxied,args));
重点Proxy.newProxyInstance,源码分析,会在其他文档中单独总结记录。类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据。
创建代理对象时序图
请点击输入图片描述
获取代理类
getProxyClass(loader, interfaces)方法用于获取代理类,它主要做了三件事情:
在当前类加载器的缓存里搜索是否有代理类,没有则生成代理类并缓存在本地JVM里。
//缓存的key使用接口名称生成的List Object key= Arrays.asList(interfaceNames);synchronized(cache){
do{
Object value= cache.get(key);
//缓存里保存了代理类的引用 if(value instanceof Reference){
proxyClass=(Class)((Reference) value).get();
}
if(proxyClass!= null){
//代理类已经存在则返回
return proxyClass;
} else if(value== pendingGenerationMarker){
//如果代理类正在产生,则等待
try{
cache.wait();
} catch(InterruptedException e){
}
continue;
} else{
//没有代理类,则标记代理准备生成
cache.put(key, pendingGenerationMarker);
break;
}
} while(true);
}
生成并加载代理类
代理类的生成主要是以下这两行代码:
//生成代理类的字节码文件并保存到硬盘中(默认不保存到硬盘) proxyClassFile= ProxyGenerator.generateProxyClass(proxyName, interfaces);//使用类加载器将字节码加载到内存中 proxyClass= defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
代理类的生成过程
ProxyGenerator.generateProxyClass()方法属于sun.misc包下,Oracle并没有提供源代码,但是我们可以使用
JD-GUI这样的反编译软件打开jre\lib\rt.jar来一探究竟,以下是其核心代码的分析。
//添加接口中定义的方法,此时方法体为空 for(int i= 0; i< this.interfaces.length; i++){localObject1= this.interfaces[i].getMethods();
for(int k= 0; k< localObject1.length; k++){
addProxyMethod(localObject1[k], this.interfaces[i]);
}
}
//添加一个带有InvocationHandler的构造方法 MethodInfo localMethodInfo= new MethodInfo("<init>","(Ljava/lang/reflect/InvocationHandler;)V", 1);
//循环生成方法体代码(省略)//方法体里生成调用InvocationHandler的invoke方法代码。(此处有所省略) this.cp.getInterfaceMethodRef("InvocationHandler","invoke","Object; Method; Object;")
//将生成的字节码,写入硬盘,前面有个if判断,默认情况下不保存到硬盘。 localFileOutputStream= new FileOutputStream(ProxyGenerator.access$000(this.val$name)+".class");
localFileOutputStream.write(this.val$classFile);
生成的代理类源码
那么通过以上分析,我们可以推出动态代理为我们生成了一个这样的代理类。把方法doSomeThing的方法体修改为调用LogInvocationHandler的invoke方法。
public class ProxyBusiness extends Proxy implements IBusiness, IBusiness2{private LogInvocationHandler h;
@Override public void doSomeThing2(){
try{
Method m=(h.target).getClass().getMethod("doSomeThing2",null);
h.invoke(this, m, null);
} catch(Throwable e){
//异常处理(略)
}
}
@Override public boolean doSomeThing(){
try{
Method m=(h.target).getClass().getMethod("doSomeThing", null);
return(Boolean) h.invoke(this, m, null);
} catch(Throwable e){
//异常处理(略)
}
return false;
}
public ProxyBusiness(LogInvocationHandler h){
this.h= h;
}
测试代理的代码如下:
//测试public static void main(String[] args){//构建AOP的Advice
LogInvocationHandler handler= new LogInvocationHandler(new Business());
new ProxyBusiness(handler).doSomeThing();
new ProxyBusiness(handler).doSomeThing2();
}
下面看一个自定义代理的实现。
被代理类接口
public interface Subject{public void doSomething();
}
被代理类
//目标对象public class RealSubject implements Subject{ public void doSomething(){System.out.println("call doSomething()");
}
}
调用处理器(切面)
public class ProxyHandler implements InvocationHandler{private Object proxied;
public ProxyHandler( Object proxied){
this.proxied= proxied;
}
public Object invoke( Object proxy, Method method, Object[] args) throws Throwable{
//在转调具体目标对象之前,可以执行一些功能处理System.out.println("doSomething before");//转调具体目标对象的方法
return method.invoke( proxied, args);
//在转调具体目标对象之后,可以执行一些功能处理System.out.println("doSomething after");
}
}
测试我们的代理实现
public class DynamicProxy{public static void main( String args[]){
RealSubject real= new RealSubject();
Subject proxySubject=(Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
new Class[]{Subject.class}, new ProxyHandler(real));
proxySubject.doSomething();//write proxySubject class binary data to file
createProxyClassFile();
}
public static void createProxyClassFile(){
String name="ProxySubject";
byte[] data= ProxyGenerator.generateProxyClass( name, new Class[]{ Subject.class});
try{
FileOutputStream out= new FileOutputStream( name+".class");
out.write( data);
out.close();
}catch( Exception e){
e.printStackTrace();
}
}
}
运行结果:
doSomething beforecall doSomething()doSomething afterProxy接口
Proxy的主要静态变量
//映射表:用于维护类装载器对象到其对应的代理类缓存private static Map loaderToCache= new WeakHashMap();//标记:用于标记一个动态代理类正在被创建中private static Object pendingGenerationMarker= new Object();//同步表:记录已经被创建的动态代理类类型,主要被方法 isProxyClass进行相关的判断private static Map proxyClasses= Collections.synchronizedMap(new WeakHashMap());//关联的调用处理器引用protected InvocationHandler h;Proxy的构造方法//由于 Proxy内部从不直接调用构造函数,所以 private类型意味着禁止任何调用private Proxy(){}//由于 Proxy内部从不直接调用构造函数,所以 protected意味着只有子类可以调用protected Proxy(InvocationHandler h){this.h= h;}
ProxySubject源码
创建的代理类 ProxySubject.class
import java.lang.reflect.*;public final class ProxySubject extends Proxy implements Subject{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
public ProxySubject(InvocationHandler invocationhandler){
super(invocationhandler);
}
public final boolean equals(Object obj){
try{
return((Boolean)super.h.invoke(this, m1, new Object[]{
obj
})).booleanValue();
}catch(Error _ex){
}catch(Throwable throwable){
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode(){
try{
return((Integer)super.h.invoke(this, m0, null)).intValue();
}catch(Error _ex){
}catch(Throwable throwable){
throw new UndeclaredThrowableException(throwable);
}
}
/*关键部分*/
public final void doSomething(){
try{
// Proxy类中protected InvocationHandler h;关联的调用处理器引用
super.h.invoke(this, m3, null);
return;
}catch(Error _ex){
}catch(Throwable throwable){
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString(){
try{
return(String)super.h.invoke(this, m2, null);
} catch(Error _ex){
} catch(Throwable throwable){
throw new UndeclaredThrowableException(throwable);
}
}
static{
try{
m1= Class.forName("java.lang.Object").getMethod("equals", new Class[]{
Class.forName("java.lang.Object")
});
m0= Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3= Class.forName("Subject").getMethod("doSomething", new Class[0]);
m2= Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
}catch(NoSuchMethodException nosuchmethodexception){
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}catch(ClassNotFoundException classnotfoundexception){
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
CGLib动态代理
动态字节码生成。使用动态字节码生成技术实现AOP原理是在运行期间目标字节码加载后,生成目标类的子类,将切面逻辑加入到子类中,所以使用Cglib实现AOP不需要基于接口。
public static void main(String[] args){byteCodeGe();
}
public static void byteCodeGe(){
//创建一个织入器
Enhancer enhancer= new Enhancer();
//设置父类
enhancer.setSuperclass(Business.class);
//设置需要织入的逻辑
enhancer.setCallback(new LogIntercept());
//使用织入器创建子类
IBusiness2 newBusiness=(IBusiness2) enhancer.create();
newBusiness.doSomeThing2();
}
/**
*记录日志
*/ public static class LogIntercept implements MethodInterceptor{
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable{
//执行原有逻辑,注意这里是invokeSuper
Object rev= proxy.invokeSuper(target, args);
//执行织入的日志
if(method.getName().equals("doSomeThing2")){
System.out.println("记录日志");
}
return rev;
}
}
关于本次java 为什么要用代理和java中为什么要给类使用代理它有哪些好处的问题分享到这里就结束了,如果解决了您的问题,我们非常高兴。