Spring Aop 源码解析
程序员文章站
2022-07-12 14:58:36
...
1. 动态代理 Jdk 和Cglib
一、原理区别:
java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
package com.lvyuanj.core.service;
public interface UserService{
void login(String username);
void exit(String username);
}
package com.lvyuanj.core.service.Impl;
import com.lvyuanj.core.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Override
public void login(String username) {
System.out.println(username+"进行登录业务验证");
}
@Override
public void exit(String username) {
System.out.println("exit---->"+username);
}
}
package com.lvyuanj.core.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target){
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start------->");
Object result = method.invoke(target, args);
System.out.println("end---------<");
return result;
}
public Object getProxy(){
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
}
}
package com.lvyuanj.core.service;
import com.lvyuanj.core.service.Impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
@EnableAspectJAutoProxy
@ComponentScan
public class SpringAopDemo {
public static void main(String[] args) throws IOException {
UserService userService0 = new UserServiceImpl();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService0);
UserService myProxyUserService = (UserService) myInvocationHandler.getProxy();
myProxyUserService.login("zhangsan");
}
}
2. Spring Aop源码解析
package com.lvyuanj.core.service;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class AuthAspect {
@Around("execution(* com.lvyuanj.core.service.Impl.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start ....");
long l = System.currentTimeMillis();
joinPoint.proceed();
System.out.println("耗时:"+ (System.currentTimeMillis()-l));
}
}
package com.lvyuanj.core.service;
import com.lvyuanj.core.service.Impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
@EnableAspectJAutoProxy
@ComponentScan
public class SpringAopDemo {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringAopDemo.class);
UserService userService = applicationContext.getBean(UserService.class);
String arvin = "arvin";
userService.login(arvin);
}
}
- 时序图:
new AnnotationConfigApplicationContext
> org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
>org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization
>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
>org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy
>org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader)
>org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
>org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy --- 判断使用JdkDynamicAopProxy 和 ObjenesisCglibAopProxy 代理;是否实现了接口
>org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader) -- 获取代理对象
>java.lang.reflect.Proxy#newProxyInstance
>java.lang.reflect.Proxy#getProxyClass0
>java.lang.reflect.Proxy.ProxyClassFactory#apply
---->byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags); --- 代理类名称获取class字节,
---->defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); -- 通过字节文件生成Class
package com.lvyuanj.core.service;
import com.lvyuanj.core.service.Impl.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
import java.io.IOException;
@EnableAspectJAutoProxy
@ComponentScan
public class SpringAopDemo {
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringAopDemo.class);
UserService userService = applicationContext.getBean(UserService.class);
String arvin = "arvin";
userService.login(arvin);
byte[] userServices = ProxyGenerator.generateProxyClass("UserServiceImpl", new Class[]{UserServiceImpl.class});
FileOutputStream fileOutputStream = new FileOutputStream("D://UserServiceImpl.class");
fileOutputStream.write(userServices);
fileOutputStream.close();
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class UserServiceImpl extends Proxy implements com.lvyuanj.core.service.Impl.UserServiceImpl {
private static Method m1;
private static Method m3;
private static Method m8;
private static Method m2;
private static Method m6;
private static Method m5;
private static Method m7;
private static Method m9;
private static Method m0;
private static Method m4;
public UserServiceImpl(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 login(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void notify() throws {
try {
super.h.invoke(this, m8, (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 void wait(long var1) throws InterruptedException {
try {
super.h.invoke(this, m6, new Object[]{var1});
} catch (RuntimeException | InterruptedException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
public final void wait(long var1, int var3) throws InterruptedException {
try {
super.h.invoke(this, m5, new Object[]{var1, var3});
} catch (RuntimeException | InterruptedException | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
public final Class getClass() throws {
try {
return (Class)super.h.invoke(this, m7, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void notifyAll() throws {
try {
super.h.invoke(this, m9, (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 final void wait() throws InterruptedException {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | InterruptedException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("login", Class.forName("java.lang.String"));
m8 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("notify");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m6 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("wait", Long.TYPE);
m5 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("wait", Long.TYPE, Integer.TYPE);
m7 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("getClass");
m9 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("notifyAll");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m4 = Class.forName("com.lvyuanj.core.service.Impl.UserServiceImpl").getMethod("wait");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
接着把得到的 $Proxy0 实例强制转换成UserServiceImpl,并将引用赋给subject。当执行userService.login()方法时,就调用了$Proxy0类中的login()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()
1.为什么我们java动态代理被代理对象必须是接口了?
答: 由于java是单继承多实现,通过上面反编译获取UserServiceImpl 代理类源码可用出来,UserServiceImpl 默认就已经继承了Proxy类,所以代理对象必须要有实现的接口;
上一篇: 常用查找算法总结
下一篇: week2实验——模拟