首先我们明确静态代理的缺点:重用性不强:
假若一个系统中有很多个目标类(service),就要一个一个的为这些service创建代理
一个service中的很多方法都需要增强,这时候代理中就会有很多的重复代码
静态代理的缺点可以通过动态代理来解决:
jdk动态代理实现:
创建目标StudentService接口并创建目标类StudentServiceImpl
public interface StudentService {
int sNums();
}
public class StudentServiceImpl implements StudentService{
@Override
public int sNums() {
int num = 3;
System.out.println("查询学生数量...");
return num;
}
}
创建实现了InvocationHandler接口实现类EnhanceHandler,通过实现接口中的invoke方法进行对StudentServiceImpl中sNums方法的增强
InvocationHandler中的invoke()方法有三个参数:
1):Object proxy :生成的代理对象
2):Method method:执行目标方法(就是需要增强的方法),通过反射中的invoke执行,
注意,这里的invoke和InvocationHandler中的invoke不一样,前者是反射中执行Method的方法
3):Object[] args:参数数组,用作method中的参数
public class EnhanceHandler implements InvocationHandler {
//要生成代理的类
Object obj = null;
public EnhanceHandler(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
int res;
//判断当前方法是否是sNums方法,是的话对其进行增强
if("sNums".equals(method.getName())) {
//利用反射调用原本的sNums方法
res = (Integer)method.invoke(obj, args);
//对method方法(sNums)进行功能增强
System.out.println("功能增强...");
res = res + 4;
}else{
//如果不是sNums方法就不进行增强
res = (Integer)method.invoke(obj,args);
}
return res;
}
}
测试
通过jdk反射包下的Proxy类中的newProxyInstance()方法创建StudentServiceImpl的代理对象
newProxyInstance()方法中需要三个参数
①:需要创建代理的类加载器
②:目标类实现的接口
③:实现了InvocationHandler接口的实现类
通过这三个参数jdk帮助我们生成StudentServiceImpl的代理对象
public class test {
public static void main(String[] args) {
//目标执行类
StudentService studentService = new StudentServiceImpl();
//自定义的实现了InvocationHandler接口的增强处理器类
EnhanceHandler handler = new EnhanceHandler(studentService);
//利用jdk反射中的代理Proxy类创建代理,强转为StudentService
//jdk代理类与目标类是兄弟关系,所以只能强转为接口类型
StudentService studentServiceProxy = (StudentService) Proxy.newProxyInstance(StudentServiceImpl.class.getClassLoader(),
StudentServiceImpl.class.getInterfaces(), handler);
//调用sNums()
int sNums = studentServiceProxy.sNums();
System.out.println(sNums);
}
}
//执行结果
/*
查询学生数量...
功能增强...
7
*/
jdk动态代理它的底层原理到底是什么,通过获取生成的代理对象,观察底层原理
/*
可以看见生成的代理类继承了Proxy并实现了StudentService接口,这就是为什么jdk动态代理中
需要生成代理的类必须实现接口,代理类通过实现目标类的实现的接口,使用反射获取到接口中的方
法,通过重写来进行目标类方法的增强。
*/
public final class $Proxy1 extends Proxy implements StudentService {
/*
可以看到其实jdk通过反射帮助我们实现了StudentService接口中的方法,并重写了equals()
hashCode(),toString()这些方法的
*/
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("LKKKK.service.StudentService").getMethod("sNums");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
/*
我们发现重写后的sNums()方法内部调用了父类中的h.invoke()方法,这里的h是什么呢?通过查看
父类Proxy发现这里的h,就是我们自定义的实现了InvocationHandler接口的EnhanceHandler对象
protected InvocationHandler h;
*/
public final int sNums() throws {
try {
/*这里也就发现我们通过生成的StudentServiceProxy代理对象调用sNums()方法其实就是调用我们
自定义的InvocationHandler中重写的invoke()方法,invoke()中的三个参数分别是this,(生成的
代理对象(本身),m3,(通过反射生成的m3 = Class.forName("LKKKK.service.StudentService").getMethod("sNums");),)
(Object[]),null其实就是sNums中的参数,这不过我们的代码中sNums()方法中并没有传参,所以
这里为null*/
return (Integer)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
//通过有参构造,将传进来的InvocationHandler对象给父类Proxy中的h属性
public $Proxy1(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
}
下面方法可以获取生成的代理对象
public static void ProxyClass(String path){
byte[] $proxy1 = ProxyGenerator.generateProxyClass("$Proxy1", StudentServiceImpl.class.getInterfaces());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File(path + "$Proxy1.class"));
fos.write($proxy1);
}catch (Exception e){
}finally {
if(fos != null){
try {
fos.close();
}catch (IOException e){
}
}
}
}