代理的概念.
代理类和实现类,都会实现同样的接口. 但是,动态代理有点不同,即,此代理类不是显式的,而是动态的,具体来讲,这个proxy是后续生成的。
要实现动态代理,就要生成一个新的类,这种方式并不常规,
我主要知道的动态的代理实现有:
1, AspectJ,这是在编译过程中新增的类,且使用的是需要第三方编译工具.
2,JDK动态代理
这篇文章是介绍jdk动态代理来.
JDK动态代理的实现例子:
一共四个类:
IUserService 接口类
UserServiceImpl 实现类,被代理的类
InvoHandlerImpl 理解为代理类
DynamicProxy main函数的类
IUserService
public interface IUserService {
public String getUserNameById(int uid);
}
UserServiceImpl:
public class UserServiceImpl implements IUserService{
@Override
public String getUserNameById(int uid) {
System.out.println("正在执行getUserNameById");
if (uid > 0) {
return "张三";
}
return "李四";
}
}
InvoHandlerImpl
public class InvoHandlerImpl implements InvocationHandler
{
/**
* 被代理对象
*/
private Object subject;
public InvoHandlerImpl(Object subject)
{
this.subject = subject;
}
/**
* 这个方法会被 生成的代理对象执行
* 调用方法时具体执行的逻辑
* 里面加上before和after
* @param proxy 代理对象
* @param method 被调用方法
* @param args 被调用方法的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
System.out.println("方法前逻辑,方法"+method);
//执行具体的逻辑
Object returnValue = method.invoke(subject, args);
System.out.println("方法后逻辑");
return returnValue;
}
}
DynamicProxy
public class DynamicProxy {
public static void main(String args[]){
IUserService userService = new UserServiceImpl();
InvoHandlerImpl invoHandler = new InvoHandlerImpl(userService);
ClassLoader loader = userService.getClass().getClassLoader();
Class[] interfaces = userService.getClass().getInterfaces();
IUserService targetService = (IUserService) Proxy.newProxyInstance(loader, interfaces, invoHandler);
System.out.println(targetService.getUserNameById(100));
}
}
上面的main函数,核心是 Proxy.newProxyInstance(…), 此方法后则返回了一个代理类
相关源码分析:
查看InvoHandlerImpl的invoke方法可知,实际是用反射机制来处理的.
当一个方法在调用的时候,通过反射机制把其Method对象取出来,然后前后加下切面逻辑后再执行这个method,则可以达到切面的效果。
- Proxy.newProxyInstance(loader, interfaces, invoHandler); 这一行做了什么?
结果来看,是生成一个Proxy类对象,同时这个类实现了IUserService接口
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, interfaces);
这一句就是通过接口生成一个设计好的代理类.在这里还没有把invoke加上去,只是生成了一个proxy类。
我们可以发现proxy类里有一个构造方法有invoke入参的,只有有这个proxy类,则调用这个构造方法,就可以返回有invoke的对象。对应的代码:
final Constructor<?> cons = cl.getConstructor(constructorParams); // constructorParams是写死的InvocationHandler.class`
....
return cons.newInstance(new Object[]{h});
- 怎么样把Proxy类加上iuserService接口的?
通过一堆debug,proxy类中 apply方法的这一段
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
三个参数,一个是代理的名称,一个是接口集
至于里面是怎么实现的,都以二进制来搞了,我就没有深入进去了,既然是byte[],应该可以打印到文件,然后来查看。总之 ProxyGenerator.generateProxyClass 这修正方法是可以直接生成代理类的。
- 代理类执行getUserById方法是什么情况
- spring的aop也是用jdk来实现了
从上面的方法可知,生成一个代理类是生成二进制的方式来做的,spring 既然要动态生成,也是需要用到这种机制了.
以下org.springframework.aop.framework.JdkDynamicAopProxy这个类的getProxy方法,可知spring 也是用jdk原生的proxy机制来处理的。
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
spring 的aop需要进一步研究,现在是看到有相应的代码关联,不确认有没有其它方式.,而且现在的spring的aop不一定要接口,这也是需要后续查看的.
参考:
https://blog.youkuaiyun.com/jiankunking/article/details/52143504