标签:stat 创建 sam with 设计模式 cep ESS 创建对象 实例
动态代理是IOC的核心,理解动态代理对于IOC的学习很有帮助。
学习动态代理之前,必须要先有反射的知识。所以我们从反射开始,一步步剖析
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
注意,反射是在运行状态中这句话。这句话的理解是:当我们平时在使用一个类的时候,我们一般的方式是:Apple a = new Apple;
这种方式。我们必须先在堆中new一个对象,并且类加载器会将此对象放到运行时内存中,比如对象放到了堆,对象的信息,引用等放到了方法区,此时的我们是知道这个对象的类型等等信息的。但是,当我们一开始不知道我们要用哪个类的时候就不能通过new来创建具体的对象了。这时候就可以通过反射来生成一个对象。
因为我们今天主要要看到是动态代理,所以,只说一些跟动态代理有关的。就是在反射的时候调用某个类的方法。
package net.xsoftlab.baike;
import java.lang.reflect.Method;
public class TestReflect {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
// 调用TestReflect类中的reflect1方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// Java 反射机制 - 调用某个类的方法1.
// 调用TestReflect的reflect2方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 20, "张三");
// Java 反射机制 - 调用某个类的方法2.
// age -> 20. name -> 张三
}
public void reflect1() {
System.out.println("Java 反射机制 - 调用某个类的方法1.");
}
public void reflect2(int age, String name) {
System.out.println("Java 反射机制 - 调用某个类的方法2.");
System.out.println("age -> " + age + ". name -> " + name);
}
}
这段代码应该对于学习了反射的人不陌生。
其中,我们可以看到核心的几句
Class<?> clazz = Class.forName("net.xsoftlab.baike.TestReflect");
// 调用TestReflect类中的reflect1方法
Method method = clazz.getMethod("reflect1");
method.invoke(clazz.newInstance());
// Java 反射机制 - 调用某个类的方法1.
// 调用TestReflect的reflect2方法
method = clazz.getMethod("reflect2", int.class, String.class);
method.invoke(clazz.newInstance(), 20, "张三");
先获取到某个类的Class对象。这个Class对象是在类加载器初次加载某个类的时候就生成了的。所以可以通过getClass或者forName来获取到。
接下来我们找到这个class代表的对象的某一个method,这个方法可以通过方法名+参数类型获得。
记住这里的核心的代码;
这里只研究动态代理的原理,不解释动态代理到底是干嘛的;
先看一段经典的动态代理代码。
public interface Inter {
void doSomething();
}
public class RealObj implements Inter {
@Override
public void doSomething() {
System.out.println("real obj func");
}
}
public class ProxyHandler implements InvocationHandler {
public ProxyHandler(Object object) {
this.object = object;
}
private Object object;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法的增强");
return method.invoke(object,args);
}
}
public class Main {
public static void main(String[] args) {
RealObj realObj = new RealObj();
Inter proxy = (Inter) Proxy.newProxyInstance(Inter.class.getClassLoader(),new Class[]{Inter.class},new ProxyHandler(realObj));
proxy.doSomething();
}
}
运行main之后的结果:
方法的增强
real obj func
Process finished with exit code 0
这里是个简单的jdk动态代理的例子。动态代理旨在不改变现有方法的情况下“增强”现有的方法。
在这里可以看到一句熟悉的话:
method.invoke(object,args);
这不就是我们反射中使用的吗。所以说,要理解动态代理必须跟反射合起来理解。
我们从main方法开始一步步分析动态代理。
在main方法中比较重要的一句话是:
Inter proxy = (Inter) Proxy.newProxyInstance(Inter.class.getClassLoader(),new Class[]{Inter.class},new ProxyHandler(realObj));
这里,使用了Proxy类的静态方法newProxyInstance()这个方法的如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
这个方法的参数需要:类加载器、接口数组、还有一个InvocationHandler实例
我认为要理解一个方法需要搞清楚其每个参数都是用来干嘛的,这样会很容易理解一个方法的作用,以及为什么要这么设计这个方法。
所以我们先看这个方法的官方注释:
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
*/
可以看到,这个方法是返回一个实现了某个接口的代理类,并且将一个分发一个method invocation给一个特定的handler。
参数:loarder:用来加载代理类
interfaces:让这个代理类要去实现的接口
h:一个用来分发激活方法的invocation handler
对于一个代理类而言,首先,我们要“有”这个代理类才可以,这里的类加载器就是用来加载这个代理类或者说生成这个代理类的。然后,我们有了一个代理类,但是怎么知道这个代理类是代理哪个类的呢?这时候就去实现被代理类实现了的接口。最后,我们的代理类是用来干什么的?是用来增强被代理类的。具体是增强被代理类的某个方法。所以,我们就需要一个Invocation handler来“定位”这个被代理类的方法。这里的定位其实就是反射的方式,去找到这个具体的方法。因为我们在反射的过程中,需要执行method.invoke(object,args);
再想一遍这个过程:
首先要有被代理类的代理类。也就是创建这个代理类对象。这里的创建对象是采用的Class<?> cl = getProxyClass0(loader, intfs);
这个来创建的。再通过反射获取到这个Class的构造方法再去创建代理类。生成的代理类再去执行InvocationHandler的invoke,但是这里执行的是接口的某一个方法,最终执行的是被代理类的某个方法并且在invoke中增强了这个方法。
写着写着感觉自己讲的有很多矛盾的地方,就先留着吧。等再变得厉害一点重新回来解决这个问题。
标签:stat 创建 sam with 设计模式 cep ESS 创建对象 实例
原文地址:https://www.cnblogs.com/GaryZz/p/11323552.html