反射、动态代理
本文注重梳理反射、动态代理的关系。
反射
反射是什么?
反射是程序在运行时可以动态的获取类的信息。包括:
- 类的属性
- 类的构造器
- 类的方法
反射可以在获取类的信息后调用其方法。
反射的应用场景
- IDEA 可以知道类的方法和属性
- 动态代理
- 待补充
反射的原理
要想了解反射的原理就需要进一步了解反射是用什么反射出来了什么?
:反射是用Java的class文件(二进制)反射出Java类的属性、方法、构造器。
Java的反射实际上做的就是从二进制文件中获取类的信息。
要想知道如何获取就要先了解class里面都有什么? 这就要设计Class类文件结构,这次先不总结。这里只要知道里面是严格按照一定格式存储的,并且包括类的所有属性和方法就可以了。如果我们知道了存储格式就可以反推出来解析方法,那么就可以解析出来类里面的所有信息了。
这里有篇文章介绍的非常好:大佬写的class介绍
动态代理
代理模式
代理模式:为其他对象提供一种代理以控制对这个对象的访问
代理模式简单来说就是对其他对象的封装。比如所有的方法执行时你都想记录开始执行时间和结束执行时间,但是这些逻辑和你的方法却没有关系,写在方法里面很难看怎么办?这时候你就需要一个代理,在被代理的类执行前后添加记录时间的方法。
是不是感觉这个就是AOP?没错AOP就是代理模式的一种实现。
这里先介绍代理模式的三种模式,后面介绍spring aop 是怎么实现的。
静态代理
静态代理 直接上代码
package cn.com.staticProxy;
/**
* *
*<p>Title: IUserDao</p>
* <p>Description:公共的接口</p>
* <p>Company: </p>
* @author Administrator
* @date 2019年4月24日 下午4:15:12
*/
public interface IUserDao {
void save();
void find();
}
package cn.com.staticProxy;
public class UserDao implements IUserDao{
/**
* 被代理类或者叫代理目标类
*/
@Override
public void save() {
// TODO Auto-generated method stub
System.out.println("模拟保存用户");
}
@Override
public void find() {
// TODO Auto-generated method stub
System.out.println("模拟查找用户");
}
}
package cn.com.staticProxy;
/**
* *
*<p>Title: Test2</p>
* <p>Description:直接使用被代理类 </p>
* <p>Company: </p>
* @author Administrator
* @date 2019年4月24日 下午4:18:39
*/
public class Test2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
IUserDao udp=new UserDao();
udp.save();
System.out.println("-------------------");
udp.find();
}
}
package cn.com.staticProxy;
public class UserDaoProxy implements IUserDao {
private UserDao ud = new UserDao();
@Override
public void save() {
// TODO Auto-generated method stub
System.out.println("代理操作,开启事务");
ud.save();
System.out.println("代理操作,关闭事务");
}
@Override
public void find() {
// TODO Auto-generated method stub
System.out.println("代理操作,开启事务");
ud.find();
System.out.println("代理操作,关闭事务");
}
}
静态代理就是人为的编写代码,调用被代理的类,并在被代理类前后添加响应信息。耦合度很高。
JDK提供的动态代理方案
静态代理说白了就是自己写一个代理类,那么对应的动态代理说白了就是有Java帮你生成一个代理类。
Java是如何帮你生成代理类的呢?这就涉及到Java类的文件结构和反射。
先贴一个整体流程,后面代码中会动态代理的输入和输出
先看一段输入代码
ICoder coder = new JavaCoder("Jack");
Objects.requireNonNull(coder);
//创建中介类实例
InvocationHandler handler = new CoderDynamicProxy(coder);
//获取类加载器
ClassLoader cl = coder.getClass().getClassLoader();
//动态产生一个代理类,或者ICoder proxy = (ICoder) new ProxyFactory(coder).getProxyInstance();
ICoder proxy = (ICoder) Proxy.newProxyInstance(cl, coder.getClass().getInterfaces(), handler);
System.out.println(proxy instanceof ICoder);
//通过代理类,执行doSomething方法;
proxy.implDemands("Modify user management");
重点看:** Proxy.newProxyInstance(cl, coder.getClass().getInterfaces(), handler) **
Proxy的newProxyInstance方法完成了代理类的生成,所以由此我们可以知道在这种情况下生成代理的输入分别是:类加载器,被代理类的class和一个实现了代理逻辑,并实现了InvocationHandler接口的类。
我们在看输出类是什么样子。
package com.sun.proxy;
import com.lanhuigu.spring.proxy.jdk.IHello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
implements IHello // 继承了Proxy类和实现IHello接口
{
// 变量,都是private static Method XXX
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
// 代理类的构造函数,其参数正是是InvocationHandler实例,Proxy.newInstance方法就是通过通过这个构造函数来创建代理实例的
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
// 以下Object中的三个方法
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
// 接口代理方法
public final void sayHello()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return ((String)this.h.invoke(this, m2, null));
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
// 静态代码块对变量进行一些初始化工作
static
{
try
{
// 这里每个方法对象 和类的实际方法绑定
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.lanhuigu.spring.proxy.jdk.IHello").getMethod("sayHello", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
输出类继承了Proxy类,并实现了被代理类的接口。而Proxy类中包含一个InvocationHandler接口。
输出类的被代理方法会调用你写好的代理方法。实际上等于生成一个中间层类。