目录
1. 前文回顾
在前面文章
Spring AOP源码分析篇二:AnnotationAwareAspectJAutoProxyCreator解析并获取advisor、切点pointcut_程序源仔的博客-CSDN博客的最后,讲到了创建动态代理有两种方式,JDK反射机制提供的动态代理和CGlib动态代理,这篇文章重要讲述一下这两种代理的区别。
回顾一下这个图,从里面知道了jdkDynamicProxy和CglibAopProxy这两个重要的类,在默认情况下,我们用的是jdk代理方式.
2. 常识
AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。静态代理是编译期实现,动态代理是运行期实现,因为在动态运行,所以性能相比静态代理差点
3. 静态代理
静态代理在编译阶段就生成了AOP代理类,也就是说生成的class字节码就织入了增强后的aop对象。
实现方式:
1、包装器模式:这个经常被用来做demo演示,需要跟被代理对象实现同一个接口,生成一个代理对象,该代理对象持有目标对象的引用,相当于包装了一层而已,该方式侵入性高,代码冗余度高
2、AspectJ静态代理方式,不是动态的运行时生成代理类,而是在编译时植入代码到class文件中。必须依赖于AspectJ自己的编译器的支持,所以很少使用。AspectJ不受类的特殊限制,方法是private、static、final都可以代理,不过他不会代理除了限定方法之外其他任何诸如roString()、clone()等方法。
4. 动态代理
动态代理则不会修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法
4.1. JDK动态代理
准备一个接口和实现类
public interface Game {
void playGame();
}
class GameImpl implements Game{
@Override
public void playGame(){
System.out.println("play game");
}
}
准备一个InvocationHandler
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {
System.out.println("method :" + method.getName() + " is invoked!");
return method.invoke( target,args );
}
}
4.1.1. 实现方式一
public static void main( String[] args ) {
Game game = (Game)Proxy.newProxyInstance(
MyInvocationHandler.class.getClassLoader(),
new Class<?>[]{Game.class},
new MyInvocationHandler( new GameImpl() )
);
game.playGame();
}
输出:
method :playGame is invoked!
play game
这种方式最常用,里面也是最出名的三大参数
展示一下jdk动态代理图
从图中可看到,invovationHandler用于做逻辑增强和目标方法调用
4.1.2. 实现方式二
public static void main( String[] args ) throws Exception{
//实现方式二
// 三个步骤:
// 1、生成代理接口的Class() class com.sun.proxy.$Proxy0
// 2、拿到构造器:public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
// 3、new一个InvocationHandler实例~~~
Class<?> proxyClass = Proxy.getProxyClass( MyInvocationHandler.class.getClassLoader(), Game.class );
Constructor<?> constructor = proxyClass.getConstructor( InvocationHandler.class );
InvocationHandler handler = new MyInvocationHandler( new GameImpl() );
Game game = (Game)constructor.newInstance( handler );
game.playGame();
}
输出:
method :playGame is invoked!
play game
方式二是方式一的底层原理
4.1.3. 反编译
反编译看一下代理类
// 1、所有JDK动态代理 都是Proxy的子类 而且是final修饰
// 2、实现了你所需要代理的接口
// 3、我们发现不管调用哪个方法,最终都是交给了InvocationHandler.invoke()方法 这也就是为什么需要我们提供这个接口的实现类的原因吧
public final class $Proxy0 extends Proxy implements Game {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
// 通过反射给Method赋值 这里我们得出结论
// Object的三个方法equals/toString/hashCode最终都是会被代理的
// m3是我们Game自己的业务方法
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.proxy.Game").getMethod("playGame");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
// 构造函数
public $Proxy0(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 void playGame() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} 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);
}
}
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);
}
}
}
从上面代码可知:
所有具体的代理方法,逻辑都是一样的,都是调用我们前面定义好的invocationHandler的invoke方法,从而触发目标对象对应的方法。
这里抛个问题:
jdk动态代理为什么只支持接口代理?
因为 他要继承Proxy类,java是单继承,所以jdk动态代理就只能代理接口了
4.1.4. Proxy类
在上面可以看到继承了Proxy类,那我们点进去看下
public class Proxy implements java.io.Serializable {
//KeyFactory和ProxyClassFactory都是内部类
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
// 我们自己实现的执行器
protected InvocationHandler h;
// 我们不能直接new它的对象
// 它里面所有的方法都是静态方法
private Proxy() {
}
// 这个构造函数由子类调用
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
// 判断是否为Proxy的子类(也就是否为JDK动态代理生成的类)
// 可以对比一下ClassUtils.isCglibProxyClass(object.getClass()) 判断是否是CGLIB对象(其实就是看名字里是否含有 "$$"这个)
public static boolean isProxyClass(Class<?> cl) {
return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
}
// 最重要的一个方法:生成代理对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 生成代理类的字节码文件
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获取代理类构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//创建代理实例
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
从上面代码可以知道,代理对象的class字节码,是在运行时动态生成的,这也是为什么我们叫做JDK动态代理的原因
我们从上面的方式一分析:进入Proxy.newProxyInstance
getProxyClass0方法是入口:需要传入类加载器和interface
//此方法也是Proxy类下的方法
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
//意思是:如果代理类被指定的类加载器loader定义了,并实现了给定的接口interfaces,
//那么就返回缓存的代理类对象,否则使用ProxyClassFactory创建代理类。
return proxyClassCache.get(loader, interfaces);
}
看一下proxyClassCache
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
proxyClassCache是个WeakCache类的对象,调用proxyClassCache.get(loader, interfaces); 可以得到缓存的代理类或创建代理类(没有缓存的情况)。
最后来到ProxyClassFactory的apply方法,代理类就是在这里生成的。
//这里的BiFunction<T, U, R>是个函数式接口,可以理解为用T,U两种类型做参数,得到R类型的返回值
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
//所有代理类名字的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
//用于生成代理类名字的计数器
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
//验证代理接口,可不看
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
//生成的代理类的包名
String proxyPkg = null; // package to define proxy class in
//代理类访问控制符: public ,final
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
//验证所有非公共的接口在同一个包内;公共的就无需处理
//生成包名和类名的逻辑,包名默认是com.sun.proxy,类名默认是$Proxy 加上一个自增的整数值
//如果被代理类是 non-public proxy interface ,则用和被代理类接口一样的包名
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
//代理类的完全限定名,如com.sun.proxy.$Proxy0.calss
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
//核心部分,生成代理类的字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//把代理类加载到JVM中,至此动态代理过程基本结束了
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
关键代码:生成二进制class数据
//生成二进制class数据流
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
generateClassFile():生产二进制数据流
saveGeneratedFiles这个字段就是生产proxy反编译文件的配置参数,默认是false
private final static boolean saveGeneratedFiles =
java.security.AccessController.doPrivileged(
new GetBooleanAction(
"sun.misc.ProxyGenerator.saveGeneratedFiles")).booleanValue();
调用native本地方法生成class对象
ProxyClassFactory
ProxyClassFactory是Proxy的一个静态内部类。它的逻辑包括了下面三步:
1、包名的创建逻辑
包名生成逻辑默认是com.sun.proxy,如果被代理类是non-public proxy interface(也就说实现的接口若不是public的,报名处理方式不太一样),则用和被代理类接口一样的包名,类名默认是$Proxy 加上一个自增的整数值
2、调用ProxyGenerator. generateProxyClass生成代理类字节码
-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 这个参数就是在该方法起到作用,如果为true则保存字节码到磁盘。代理类中,所有的代理方法逻辑都一样都是调用invocationHander的invoke方法(上面源码我们也能看出来)
3、把代理类字节码加载到JVM。
把字节码通过传入的类加载器加载到JVM中:defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
4.2. CGLIB代理
写一个CGLib内部使用的增强器
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 注意:这个是org.springframework.cglib.proxy.MethodInterceptor
// 而不是org.aopalliance.intercept包下的
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept( Object o, Method method, Object[] objects, MethodProxy methodProxy ) throws Throwable {
// 此处千万不能调用method得invoke方法,否则会死循环的 只能使用methodProxy.invokeSuper 进行调用
Object intercept = methodProxy.invokeSuper( o,objects );
System.out.println("拦截器生效..");
return intercept;
}
}
main方法执行
import org.springframework.cglib.proxy.Enhancer;
// 此处需要说明:Enhancer实际属于CGLIB包的,也就是`net.sf.cglib.proxy.Enhancer`
// 但是Spring把这些类都拷贝到自己这来了,因此我用的Spring的Enhancer,包名为;`org.springframework.cglib.proxy.Enhancer`
public class EnhancerMain {
public static void main( String[] args ) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass( GameImpl.class );
enhancer.setCallback( new MyMethodInterceptor() );
Game game = (Game)enhancer.create();
game.playGame();
}
}
输出
play game
拦截器生效..
5. Aoproxy
AopProxy:aop代理接口,提供了两个方法让我们获取aop代理对象(都是动态代理)
public interface AopProxy {
Object getProxy();
Object getProxy(@Nullable ClassLoader classLoader);
}
继承关系,接下来就是要讲这几个
先写个demo,看一下Spring Aop环境
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.SpringProxy;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.core.DecoratingProxy;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class ProxyFactoryMain {
public static void main( String[] args ) {
ProxyFactory proxyFactory = new ProxyFactory(new Hello());
proxyFactory.addAdvice((MethodBeforeAdvice) (method, args1, target) ->
System.out.println("你被拦截了:方法名为:" + method.getName() + " 参数为--" + Arrays.asList(args1)));
HelloInterface hello = (HelloInterface)proxyFactory.getProxy();
hello.hello();
System.out.println(proxyFactory.getTargetClass()); //class com.xiaoyuanzai.service.InvocationHandler.Hello
System.out.println(proxyFactory.getTargetSource()); //SingletonTargetSource for target object [com.xiaoyuanzai.service.InvocationHandler.Hello@5d099f62]
System.out.println(proxyFactory.getAdvisorCount()); //1
System.out.println(Arrays.asList( proxyFactory.getAdvisors() )); //[org.springframework.aop.support.DefaultPointcutAdvisor: pointcut [Pointcut.TRUE]; advice [com.xiaoyuanzai.service.InvocationHandler.ProxyFactoryMain$$Lambda$1/1199823423@37f8bb67]]
System.out.println(".......................................");
//代理类的接口HelloInterface、 SpringProxy、Advised、DecoratingProxy
System.out.println(Arrays.asList( hello.getClass().getInterfaces() )); //[interface com.xiaoyuanzai.service.InvocationHandler.HelloInterface, interface org.springframework.aop.SpringProxy, interface org.springframework.aop.framework.Advised, interface org.springframework.core.DecoratingProxy]
System.out.println(hello instanceof Proxy ); //true
System.out.println(hello instanceof SpringProxy ); //true org.springframework.aop.SpringProxy这个是marker接口,空的,不用管,只是做个标记,框架会用到
System.out.println(hello instanceof DecoratingProxy ); //true
System.out.println(hello instanceof Advised ); //true
System.out.println(hello.getClass());//class com.xiaoyuanzai.service.InvocationHandler.$Proxy0
System.out.println(Proxy.isProxyClass( hello.getClass() ));//true
System.out.println( AopUtils.isCglibProxy( hello ) );//false
System.out.println(".......................................");
//测试Advised接口、DecoratingProxy的内容
Advised advised = (Advised)hello;
System.out.println(advised.isExposeProxy()); //false
System.out.println(advised.isFrozen()); //false
System.out.println(".......................................");
// Object的方法 ==== 所有的Object方法都不会被AOP代理(除了toString()) 这点需要注意
System.out.println(hello.equals( new Object() ));//false
System.out.println(hello.hashCode());
System.out.println(hello.getClass());
//其余方法都没被拦截 只有toString()被拦截了
//你被拦截了:方法名为:toString 参数为--[]
//com.xiaoyuanzai.service.InvocationHandler.Hello@5d099f62
System.out.println(hello.toString());
}
}
interface HelloInterface{
void hello();
}
class Hello implements HelloInterface{
@Override
public void hello(){
System.out.println("Hello world");
}
}
上面逻辑生成的就是JDK动态代理对象,核心就两步
1.addAdvice():添加advice前置通知器,并包装成DefaultPointcutAdvisor交给ProxyCreatorSupport
2.getProxy():本文关键,内部会new一个JdkDynmicAopProxy,并调用它的getProxy()获取动态代理对象,他JdkDynmicAopProxy实现了InvocationHandler接口,当调用目标方法时,会触发invocationHandler的invoke()方法,该方法内部会执行第一步添加的前置通知器,并最终执行原目标方法
5.1. JdkDynamicAopProxy
进入源码看看
// 它自己实现了InvocationHandler,处理器就是它自己,所以他会实现invoke方法
// final关键字代表了 包的访问权限
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
/** use serialVersionUID from Spring 1.2 for interoperability. */
private static final long serialVersionUID = 5531744639992436476L;
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
/** 保存当前AOP代理所有的配置信息 包括所有的增强器等等 */
private final AdvisedSupport advised;
private final Class<?>[] proxiedInterfaces;
/** true:标记equals方法定义在接口上 */
private boolean equalsDefined;
/** true:hashCode方法定义在接口上 */
private boolean hashCodeDefined;
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
// 必须有至少一个增强器 或者 目标实例,否则抛错
if (config.getAdvisorCount() == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
// 这步就是去找 获取aop所有需要代理的接口
// 最终Proxy的接口就是这里返回的所有接口(除了自己定义的接口,还有Spring默认的一些接口)
// 大致过程如下:
//1、获取Target对象自己实现的所有接口
//2、是否添加`SpringProxy`这个接口:目标对象实现过就不添加了,没实现过就添加true
//3、是否新增`Adviced`接口,注意不是Advice通知接口。 实现过就不实现了,没实现过并且advised.isOpaque()=false就添加(默认是会添加的)
//4、是否新增DecoratingProxy接口。传入的参数decoratingProxy为true,并且没实现过就添加(显然这里,首次进来是会添加的)
//5、代理类的接口一共是目标对象的接口+上面三个接口SpringProxy、Advised、DecoratingProxy(SpringProxy是个标记接口而已,其余的接口都有对应的方法的)
//DecoratingProxy 这个接口Spring4.3后才提供
this.proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(this.proxiedInterfaces);
}
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
/** 真正创建JDK动态代理实例的地方 */
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
// this实现了InvocationHandler,处理器(InvocationHandler)就是自己,并new一个代理对象
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
// 找接口里有没有自己定义equals方法和hashCode方法,标记为true
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
// 判断被代理的接口中是否定义了equals()、hashCode()方法,如果程序员在接口中手动定义了这两个方法,则也会进行代理
// 否则这两个方法是不会走代理逻辑的
for (Class<?> proxiedInterface : proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
//两个方法都找到就不用继续循环
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}
/**
* 这部分代码和采用CGLIB的大部分逻辑都是一样的
*/
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
// 拿到被代理对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 如果接口中没有定义equals()方法,且 实现类自己实现equals()方法则调用AOP这里的实现
// hashCode同理
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
return hashCode();
}
//DecoratingProxy的方法和Advised接口的方法 都是是最终调用了this.advised去执行的
else if (method.getDeclaringClass() == DecoratingProxy.class) {
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// 也是直接调用Advised接口中的方法,不走代理逻辑
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
// 如果ProxyFactory的exposeProxy为true,则将代理对象设置到currentProxy这个ThreadLocal中去
if (this.advised.exposeProxy) {
//把我们的代理对象暴露到线程变量中
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 被代理对象和代理类
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 代理对象在执行某个方法时,根据方法筛选出所有匹配的Advisor(通知advice+切入点pointcut),并适配成Interceptor,通过责任链模式 依此获取到
// 参见DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
//拦截器链为空
if (chain.isEmpty()) {
// 如果没有Advice,则直接调用目标方法
// 对参数适配:处理一些数组类型的参数,表示一个(多个)参数(可变参数最终到此都是数组类型,所以最好是需要一次适配)
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//直接调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//MethodInvocation是org.aopalliance.intercept这个包下的AOP联盟得标准接口
// 创建一个ReflectiveMethodInvocation
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 递归执行所有的拦截器链chain,则前置、后置等通知
retVal = invocation.proceed();
}
// 获取返回值的类型
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 如果返回值不为空,且为目标对象的话,就直接将目标对象赋值给retVal
retVal = proxy;
}
// 返回值=null 且不是Void类型 抛错
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
// 释放
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
// 把老的代理对象重新set进去
if (setProxyContext) {
AopContext.setCurrentProxy(oldProxy);
}
}
}
// AOP帮我们实现的equals方法
@Override
public boolean equals(@Nullable Object other) {
if (other == this) {
return true;
}
if (other == null) {
return false;
}
JdkDynamicAopProxy otherProxy;
if (other instanceof JdkDynamicAopProxy) {
otherProxy = (JdkDynamicAopProxy) other;
}
else if (Proxy.isProxyClass(other.getClass())) {
// other是一个jdk动态代理产生的代理对象
InvocationHandler ih = Proxy.getInvocationHandler(other);
if (!(ih instanceof JdkDynamicAopProxy)) {
return false;
}
otherProxy = (JdkDynamicAopProxy) ih;
}
else {
// Not a valid comparison...
return false;
}
// If we get here, otherProxy is the other AopProxy.
return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);
}
// AOP帮我们实现的HashCode方法
@Override
public int hashCode() {
return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
}
}
注意:
1.生成出来的代理对象Spring都默认实现了接口:SpringProxy、DecoratingProxy、Advised,而CGLIB代理对象没有实现DecoratingProxy
2.里面两个重要方法,getProxy()方法负责拿到代理对象,invoke()方法负责在每次代理方法被调用时执行(除了实现类里自己写的方法(接口上没有的),其余方法统一都会进入代理得invoke()方法里面)
3.Object的toString()方法会被增强
5.2. ObjenesisCglibAopProxy
这个是CGLIB的demo,注意看里面没有接口类了,是通过生成代理类的class对象的形式,生成代理对象
main方法
public class ProxyFactoryMain {
public static void main( String[] args ) {
ProxyFactory proxyFactory = new ProxyFactory(new Hello());
proxyFactory.addAdvice( ( MethodBeforeAdvice )( method, args1, target ) -> {
System.out.println( "你被拦截了:方法名为:" + method.getName() + " 参数为--" + Arrays.asList( args1 ) );
} );
Hello hello = (Hello)proxyFactory.getProxy();
hello.hello();
}
}
class Hello {
public void hello() {
System.out.println( "Hello world" );
}
}
在代码中可以看到ObjenesisCglibAopProxy继承了CglibAopProxy,重写了createProxyClassAndInstance()方法,用于生成代理实例
/**
* ObjenesisCglibAopProxy是Spring4.0之后提供的
*/
@SuppressWarnings("serial")
class ObjenesisCglibAopProxy extends CglibAopProxy {
private static final Log logger = LogFactory.getLog(ObjenesisCglibAopProxy.class);
private static final SpringObjenesis objenesis = new SpringObjenesis();
/**
* Create a new ObjenesisCglibAopProxy for the given AOP configuration.
* @param config the AOP configuration as AdvisedSupport object
*/
public ObjenesisCglibAopProxy(AdvisedSupport config) {
super(config);
}
//看方法名就知道:实例化一个代理对象
@Override
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
Class<?> proxyClass = enhancer.createClass();
Object proxyInstance = null;
// true:用objenesis去new一个实例
if (objenesis.isWorthTrying()) {
try {
proxyInstance = objenesis.newInstance(proxyClass, enhancer.getUseCache());
}
catch (Throwable ex) {
logger.debug("Unable to instantiate proxy using Objenesis, " +
"falling back to regular proxy construction", ex);
}
}
// 如果proxyInstance还为null,再去拿到构造函数去new一个实例(指定参数的)
if (proxyInstance == null) {
// Regular instantiation via default constructor...
try {
Constructor<?> ctor = (this.constructorArgs != null ?
proxyClass.getDeclaredConstructor(this.constructorArgTypes) :
proxyClass.getDeclaredConstructor());
ReflectionUtils.makeAccessible(ctor);
// 通过此构造函数 去new一个实例
proxyInstance = (this.constructorArgs != null ?
ctor.newInstance(this.constructorArgs) : ctor.newInstance());
}
catch (Throwable ex) {
throw new AopConfigException("Unable to instantiate proxy using Objenesis, " +
"and regular proxy instantiation via default constructor fails as well", ex);
}
}
((Factory) proxyInstance).setCallbacks(callbacks);
return proxyInstance;
}
}
5.3. CglibAopProxy
这个类处理核心操作,getProxy()负责获取代理对象实例,DynamicAdvisedInterceptor#intercept()负责拦截目标方法做方法增强
class CglibAopProxy implements AopProxy, Serializable {
@Override
public Object getProxy() {
return getProxy(null);
}
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating CGLIB proxy: " + this.advised.getTargetSource());
}
try {
// 被代理的类
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
// 如果被代理类本身就已经是Cglib所生成的代理类了
if (rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) {
// 获取真正的被代理类
proxySuperClass = rootClass.getSuperclass();
// 获取被代理类所实现的接口
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
// 被代理类,代理类的父类
enhancer.setSuperclass(proxySuperClass);
// 代理类额外要实现的接口
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
// 获取和被代理类所匹配的Advisor
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
return (this.constructorArgs != null && this.constructorArgTypes != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}
/**
* Creates the CGLIB {@link Enhancer}. Subclasses may wish to override this to return a custom
* {@link Enhancer} implementation.
*/
protected Enhancer createEnhancer() {
return new Enhancer();
}
/** CGLIB重写这个方法 */
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof CglibAopProxy &&
AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised)));
}
/** CGLIB重写这个方法 */
@Override
public int hashCode() {
return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
}
/**
* 所有被代理的类(Target)的所有方法调用,都会进入DynamicAdvisedInterceptor#intercept()方法中(相当于JDK动态代理得invoke方法)
*/
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
// 目标对象源
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 拿到目标对象 这里就是使用targetSource的意义,它提供多个实现类,从而实现了更多的可能性
// 比如:SingletonTargetSource HotSwappableTargetSource PrototypeTargetSource ThreadLocalTargetSource等等
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 跟JdkDynamicAopProxy的invoke()方法的调用一样,获取拦截器
// 代理对象在执行某个方法时,根据方法筛选出所有匹配的Advisor(通知advice+切入点pointcut),并适配成Interceptor,通过责任链模式 依此获取到
// 参见DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice方法
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// 增强器链是空,且该方法是public
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
// 直接调用目标方法
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// CglibMethodInvocation是`ReflectiveMethodInvocation`的子类 这里就和JDK Proxy保持一致
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
}
/**
* CGLIB uses this to drive proxy creation.
*/
@Override
public int hashCode() {
return this.advised.hashCode();
}
}
注意:
1.和jdk一样只有toString()方法会被拦截
2.默认实现了SpringProxy、Advised接口
3.它和JDK不同的是,比如equals和hashCode等方法根本就不会进入intecept方法,而是在getCallbacks()那里就给特殊处理掉了
5.3.1. Objenesis
上面源码有提到SpringObjenesis,那下面就来具体讲一下。
创建对象有好多种方式,如new一个对象,通过构造器反射获取一个对象,又或者是用Objenesis的方式生成对象(绕过构造函数来创建对象)
Objenesis库可以在以下情况下用来实例化对象:
1. 对象没有无参构造函数:如果一个类没有公共的无参构造函数,那么使用传统的反射机制将无法直接实例化该对象。在这种情况下,Objenesis可以通过创建一个未完全初始化的对象进行实例化。
2. 构造函数不可访问(构造函数为private):有些类可能将它们的构造函数设置为私有或受保护的,这使得使用传统的反射方法来创建对象变得非常困难(class.newInstance)。Objenesis可以绕过构造函数的访问级别限制,使您可以实例化这些对象。
3. 性能优化:使用传统的反射机制创建对象时,Java虚拟机需要执行一系列复杂的操作来初始化对象。这可能会影响应用程序的性能。使用Objenesis库,您可以更高效地创建对象并提高应用程序的性能。
总之,Objenesis可用于那些没有公共的无参数构造函数或构造函数不可用的对象,或者需要更高效的对象实例化的情况下。
5.3.1.1. ObjenesisStd
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
public class Main {
public static void main(String[] args) throws Exception {
//创建一个Objenesis实例
Objenesis objenesis = new ObjenesisStd();
//使用Objenesis创建一个对象(注意:没有调用构造函数)
MyClass myClass = objenesis.newInstance(MyClass.class);
//使用反射来设置对象的属性
myClass.setName("My Object");
myClass.setValue(123);
//打印输出对象的属性
System.out.println(myClass.getName()); //输出:My Object
System.out.println(myClass.getValue()); //输出:123
}
}
class MyClass {
private String name;
private int value;
private MyClass() {
//私有构造函数
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
5.3.1.2. ObjectInstantiator
ObjectInstantiator是Objenesis库提供的一个接口,可以用来创建特定类型的对象实例。和直接调用Objenesis.newInstance()方法不同,使用ObjectInstantiator可以更方便地重复创建同一类型的对象。ObjectInstantiator有一个唯一的方法newInstance(),它可以创建一个新的对象实例,不同的是,每次调用newInstance()时,都会返回一个新的实例。
public interface ObjectInstantiator<T> {
T newInstance();
}
demo如下:
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.objenesis.instantiator.ObjectInstantiator;
public class Main {
public static void main(String[] args) throws Exception {
//创建一个Objenesis实例
Objenesis objenesis = new ObjenesisStd();
//使用Objenesis创建一个ObjectInstantiator实例
ObjectInstantiator<MyClass> myClassInstantiator =
objenesis.getInstantiatorOf(MyClass.class);
//使用ObjectInstantiator创建多个MyClass对象
MyClass myClass1 = myClassInstantiator.newInstance();
MyClass myClass2 = myClassInstantiator.newInstance();
MyClass myClass3 = myClassInstantiator.newInstance();
//打印输出对象的属性
System.out.println(myClass1.getName()); //输出:null
System.out.println(myClass2.getValue()); //输出:0
System.out.println(myClass3.getName()); //输出:null
}
}
class MyClass {
private String name;
private int value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
在上面的示例中,我们使用Objenesis创建了一个ObjectInstantiator实例,然后使用该实例重复创建MyClass对象。在每次调用newInstance()方法时,都会返回一个新的MyClass对象实例。
所有的Objenesis类都在org.objenesis包中
5.3.1.3. SpringObjenesis
这是Spring对Objenesis接口的一个实现
Objenesis objenesis = new SpringObjenesis();
Spring为我们提供了一个isWorthTrying()方法:
// 是否需要尝试:也就是说,它是否还没有被使用过,或者已知是否有效。方法返回true,表示值得尝试
// 如果配置的Objenesis Instantiator策略被确定为不处理当前JVM。或者系统属性"spring.objenesis.ignore"值设置为true,表示不尝试了
// 这个在ObjenesisCglibAopProxy创建代理实例的时候用到了。若不尝试使用Objenesis,那就还是用老的方式用空构造函数吧
public boolean isWorthTrying() {
return (this.worthTrying != Boolean.FALSE);
}
利用SpringObjenesis,即使没有空的构造函数也可以创建实例。
注意
JDK代理只能针对实现了接口的类以反射的方式生成代理,而不能针对类 ,所以也叫接口代理。
CGLIB是针对类实现代理的,主要对指定的类以字节码转换的方式(ASM框架)生成一个子类,并重写其中的方法。
所以使用CGLIB做动态代理,必须要保证有一个空的构造函数。(那是之前,其实现在不需要了,因为我们有了Objenesis的帮助),但是类不能是Final的
关于final方法
- JDK代理:因为接口的方法不能使用final关键字,所以编译器就过不去
- CGLIB代理:final修饰某个方法后,不报错。但也不会拦截了
关于static方法
- JDK代理:static修饰接口上的方法,要求有body体(JDK8后支持)。但是因为子类不能@Override了,所以编译就报错了
- CGLIB代理:父类方法用static修饰后,子类也是无法进行重写的。因此不报错,但也不会拦截了
使用代理的时候,尽量不要使用final和static关键字
关于非public方法
- JDK代理:接口中的方法都是public的,所以对于它不存在这种现象
- CGLIB代理:记住结论 只有private的方法不能被代理(因为子类无法访问),其余的访问权限级别的,都能够被正常代理。 简单的说就是只要子类能够访问的权限,都能够被正常代理
6. 总结
1、JdkDynamicAopProxy 入口方法是 invoke() 方法,CGLIB 使用的是 DynamicAdvisedInterceptor.intercept()方法
2、JdkDynamicAopProxy使用的MethodInvocation 是: ReflectiveMethodInvocation 子类,
CGLIB 使用的是CglibMethodInvocation,它俩都是ProxyMethodInvocation接口的实现类。并且CglibMethodInvocation是继承自ReflectiveMethodInvocation的