JDK中的动态代理
用法:
public class MyProxy {
public interface IHello{
void sayHello();
}
static class Hello implements IHello{
public void sayHello() {
System.out.println("Hello world!!");
}
}
//自定义InvocationHandler
static class HWInvocationHandler implements InvocationHandler{
//目标对象
private Object target;
public HWInvocationHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("------插入前置通知代码-------------");
//执行相应的目标方法
Object rs = method.invoke(target,args);
System.out.println("------插入后置处理代码-------------");
return rs;
}
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetExc eption, InstantiationException {
//生成$Proxy0的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
//获取动态代理类
Class proxyClazz = Proxy.getProxyClass(IHello.class.getClassLoader(),IHello.class);
//获得代理类的构造函数,并传入参数类型InvocationHandler.class
Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
//通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
IHello iHello = (IHello) constructor.newInstance(new HWInvocationHandler(new Hello()));
//通过代理对象调用目标方法
iHello.sayHello();
}
}
JDK在实现动态代理时,总流程便是先使用接口类生成代理类的class文件(其中包含接口中声明的需要代理的方法及toString、hashCode等三个Object方法),然后在生成代理类时将实现了InvocationHandler接口的逻辑代理类放入构造器中,反射生成Proxy对象,Proxy对象中含有逻辑代理类对象(一个InvocationHandler对象),在调用Proxy的相关方法时,Proxy就会调用逻辑代理对象中的方法,而我们在逻辑代理对象中已经设置了相关代理逻辑,接着等待调用完成就可以了。
$Proxy0.class:
public final class $Proxy0 extends Proxy implements IHello { //继承了Proxy类和实现IHello接口
//变量,都是private static Method XXX
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2;
//代理类的构造函数,其参数正是是InvocationHandler实例,Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
//接口代理方法
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//以下Object中的三个方法
public final boolean equals(Object var1) throws {
try {
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final int hashCode() throws {
try {
return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//对变量进行一些初始化工作
static {
try {
m3 = Class.forName("com.mobin.proxy.IHello").getMethod("sayHello", new Class[0]);
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]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
参考:https://www.cnblogs.com/MOBIN/p/5597215.html
在根据接口创建代理类的class文件时有许多步骤,首先会进行一些安全的权限检查,接着需要验证我们传入的接口class数组中的接口是否都是由我们传入的类加载器加载的,以及该class对象是否是接口、接口是否重复等等,然后设置代理类的名称(代理类的包路径)等等,最后,生成代理类的字节码文件,如下方法,便在字节码中放入了一个可传入逻辑代理类对象的构造器,以及接口中存在的各种方法,也就是我们需要代理的各方法。此时,代理类对象创建完毕,返回上层源码,我们最终又获取了字节码中的构造器,在newInstance方法中传入了该构造器和需要接收的对象,即我们创建的逻辑代理类对象,此时,代理类对象创建完毕,返回该Proxy。
private byte[] generateClassFile() {
/addProxyMethod系列方法就是将接口的方法和Object的hashCode,equals,toString方法添加到代理方法容器(proxyMethods),
其中方法签名作为key,proxyMethod作为value*/
/*hashCodeMethod方法位于静态代码块中通过Object对象获得,hashCodeMethod=Object.class.getMethod("hashCode",new Class[0]),
相当于从Object中继承过来了这三个方法equalsMethod,toStringMethod*/
this.addProxyMethod(hashCodeMethod, Object.class); -->
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
int var1;
int var3;
//获得所有接口中的所有方法,并将方法添加到代理方法中
for(var1 = 0; var1 < this.interfaces.length; ++var1) {
Method[] var2 = this.interfaces[var1].getMethods();
for(var3 = 0; var3 < var2.length; ++var3) {
this.addProxyMethod(var2[var3], this.interfaces[var1]);
}
}
Iterator var7 = this.proxyMethods.values().iterator();
List var8;
while(var7.hasNext()) {
var8 = (List)var7.next();
checkReturnTypes(var8); //验证具有相同方法签名的的方法的返回值类型是否一致,因为不可能有两个方法名相同,参数相同,而返回值却不同的方法
};
//接下来就是写代理类文件的步骤了
Iterator var11
try {
//生成代理类的构造函数
this.methods.add(this.generateConstructor());
var7 = this.proxyMethods.values().iterator();
while(var7.hasNext()) {
var8 = (List)var7.next();
var11 = var8.iterator();
while(var11.hasNext()) {
ProxyGenerator.ProxyMethod var4 = (ProxyGenerator.ProxyMethod)var11.next();
/将代理字段声明为Method,10为ACC_PRIVATE和ACC_STATAIC的与运算,表示该字段的修饰符为private static
所以代理类的字段都是private static Method XXX*/
this.fields.add(new ProxyGenerator.FieldInfo(var4.methodFieldName, "Ljava/lang/reflect/Method;", 10));
//生成代理类的代理方法
this.methods.add(var4.generateMethod());
}
}
//为代理类生成静态代码块,对一些字段进行初始化
this.methods.add(this.generateStaticInitializer());
} catch (IOException var6) {
throw new InternalError("unexpected I/O Exception");
}
if(this.methods.size() > '\uffff') { //代理方法超过65535将抛出异常
throw new IllegalArgumentException("method limit exceeded");
} else if(this.fields.size() > '\uffff') { //代理类的字段超过65535将抛出异常
throw new IllegalArgumentException("field limit exceeded");
} else {
//这里开始就是一些代理类文件的过程,此过程略过
this.cp.getClass(dotToSlash(this.className));
this.cp.getClass("java/lang/reflect/Proxy");
for(var1 = 0; var1 < this.interfaces.length; ++var1) {
this.cp.getClass(dotToSlash(this.interfaces[var1].getName()));
}
this.cp.setReadOnly();
ByteArrayOutputStream var9 = new ByteArrayOutputStream();
DataOutputStream var10 = new DataOutputStream(var9);
try {
var10.writeInt(-889275714);
var10.writeShort(0);
var10.writeShort(49);
this.cp.write(var10);
var10.writeShort(49);
var10.writeShort(this.cp.getClass(dotToSlash(this.className)));
var10.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
var10.writeShort(this.interfaces.length);
for(var3 = 0; var3 < this.interfaces.length; ++var3) {
var10.writeShort(this.cp.getClass(dotToSlash(this.interfaces[var3].getName())));
}
var10.writeShort(this.fields.size());
var11 = this.fields.iterator();
while(var11.hasNext()) {
ProxyGenerator.FieldInfo var12 = (ProxyGenerator.FieldInfo)var11.next();
var12.write(var10);
}
var10.writeShort(this.methods.size());
var11 = this.methods.iterator();
while(var11.hasNext()) {
ProxyGenerator.MethodInfo var13 = (ProxyGenerator.MethodInfo)var11.next();
var13.write(var10);
}
var10.writeShort(0);
return var9.toByteArray();
} catch (IOException var5) {
throw new InternalError("unexpected I/O Exception");
}
}
}
Spring IOC的实现原理
从最广泛的角度上将,spring ioc(控制反转)就是将对象声明周期的掌控权交给Spring框架管理,而不是程序员new对象了,在需要创建对象时,Spring便会将对象注入到当前的引用中,实现对象间的解耦。单例对象会被Spring放在一个单例Bean的缓存器,单例Bean通过beanName作为key保存在这个HashMap中。属性为prototype的Bean没有缓存器。
实例化Bean的流程:
- Resourceloader从存储介质中加载Spring配置信息,并使用Resource表示这个配置文件的资源;
- BeanDefinitionReader读取Resource所指向的配置文件资源,然后解析配置文件。配置文件中每一个解析成一个BeanDefinition对象,并保存到BeanDefinitionRegistry中。(BeanDefinition中包括所有Bean可配置的属性,例如是否单例、是否延迟加载等等,其相当于一个Java可调用版的XML配置文件,在生成Bean时需要访问其中的各种属性);
- 容器扫描BeanDefinitionRegistry中的BeanDefinition ,使用Java的反射机制自动识别出Bean工厂后处理器(实现BeanFactoryPostProcessor接口)的Bean ,然后调用这些Bean工厂后处理器对BeanDefinitionRegistry中的BeanDefinition进行加工处理。主要完成以下两项工作:
1)对使用到占位符的元素标签进行解析,得到最终的配置值,这意味对一些半成品式的BearDefinition对象进行加工处理并得到成品的BeanDefinition对象;
2)对BeanDefinitionRegistry中的BeanDefinition进行扫描,通过Java反射机制找出所有属性编辑器的Bean (实现java.beans.PropertyEditor接口的Bean ) ,并自动将它们注册到Spring容器的属性编辑器注册表中(PropertyEditorRegistry ) ; - Spring容器从BeanDefinitionRegistry中取出加工后的BeanDefinition ,并调用Instantiationstrategy着手进行Bean实例化的工作;
- 在实例化Bean时, Spring容器使用BeanWrapperBean进行封装, BeanWrapper提供了很多以ava反射机制操作Bean的方法,它将结合该Bean的BeanDefinition以及容器中属性编辑器,完成Bean属性的设置工作;
- 利用容器中注册的Bean后处理器(实现BeanPostProcessor接口的Bean )对已经完成属性设置工作的Bean进行加工,直接装配出一个准备就绪的Bean。