点击上方 Java后端,选择 设为星标
优质文章,及时送达
最近在开发中遇到了一个刚好可以用AOP实现的例子,就顺便研究了AOP的实现原理,把学习到的东西进行一个总结。文章中用到的编程语言为kotlin,需要的可以在IDEA中直接转为java。
这篇文章将会按照如下目录展开:
AOP简介
代码中实现举例
AOP实现原理
部分源码解析
1. AOP简介
前置通知:@Before 在目标业务方法执行之前执行
后置通知:@After 在目标业务方法执行之后执行
返回通知:@AfterReturning 在目标业务方法返回结果之后执行
异常通知:@AfterThrowing 在目标业务方法抛出异常之后
环绕通知:@Around 功能强大,可代替以上四种通知,还可以控制目标业务方法是否执行以及何时执行
2. 代码中实现举例
@Target(AnnotationTarget.FUNCTION)
//注解作用的范围,这里声明为函数
@Order(Ordered.HIGHEST_PRECEDENCE)
//声明注解的优先级为最高,假设有多个注解,先执行这个
annotation class Hanler(val handler: HandlerType)
//自定义注解类,HandlerType是一个枚举类型,里面定义的就是学生和老师的增删改操作,在这里就不展示具体内容了
@Aspect //该注解声明这个类为一个切面类
@Component
class HandlerAspect{
@Autowired
private lateinit var handlerService: HandlerService
@AfterReturning("@annotation(handler)") //当有函数注释了注解,将会在函数正常返回后在执行我们定义的方法
fun hanler(hanler: Hanler) {
handlerService.add(handler.operate.value) //这里是真正执行记录的方法
}
}
/**
* 删除学生方法
*/
@Handler(operate= Handler.STUDENT_DELETE) //当执行到删除学生方法时,切面类就会起作用了,当学生正常删除后就会执行记录方法,我们就可以看到记录方法生成的数据
fun delete(id:String) {
studentService.delete(id)
}
3. AOP实现原理
subject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口;
RealSubject:真实主题角色,是实现抽象主题接口的类;
Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。
3.1 静态代理
/**
* 创建person接口
*/
public interface Person {
//交作业
void giveTask();
}
public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
public void giveTask() {
System.out.println(name + "交语文作业");
}
}
/**
* 学生代理类,也实现了Person接口,保存一个学生实体,这样就可以代理学生产生行为
*/
public class StudentsProxy implements Person{
//被代理的学生
Student stu;
public StudentsProxy(Person stu) {
// 只代理学生对象
if(stu.getClass() == Student.class) {
this.stu = (Student)stu;
}
}
//代理交作业,调用被代理学生的交作业的行为
public void giveTask() {
stu.giveTask();
}
}
public class StaticProxyTest {
public static void main(String[] args) {
//被代理的学生林浅,他的作业上交有代理对象monitor完成
Person linqian = new Student("林浅");
//生成代理对象,并将林浅传给代理对象
Person monitor = new StudentsProxy(linqian);
//班长代理交作业
monitor.giveTask();
}
}
3.2 动态代理
/**
* 创建person接口
*/
public interface Person {
//交作业
void giveTask();
}
public class Student implements Person {
private String name;
public Student(String name) {
this.name = name;
}
public void giveTask() {
System.out.println(name + "交语文作业");
}
}
public class StuInvocationHandler<T> implements InvocationHandler {
//invocationHandler持有的被代理对象
T target;
public StuInvocationHandler(T target) {
this.target = target;
}
/**
* proxy:代表动态代理对象
* method:代表正在执行的方法
* args:代表调用目标方法时传入的实参
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理执行" +method.getName() + "方法");
Object result = method.invoke(target, args);
return result;
}
}
/**
* 代理类
*/
public class ProxyTest {
public static void main(String[] args) {
//创建一个实例对象,这个对象是被代理的对象
Person linqian = new Student("林浅");
//创建一个与代理对象相关联的InvocationHandler
InvocationHandler stuHandler = new StuInvocationHandler<Person>(linqian);
//创建一个代理对象stuProxy来代理linqian,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
//代理执行交作业的方法
stuProxy.giveTask();
}
}
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);
}
/*
* Look up or generate the designated proxy class.
*/
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<?> cl = getProxyClass0(loader, intfs)
这句代码,这里产生了代理类,这个类就是动态代理的关键,由于是动态生成的类文件,我们将这个类文件打印到文件中。
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", Student.class.getInterfaces());
String path = "/Users/mapei/Desktop/okay/65707.class";
try{
FileOutputStream fos = new FileOutputStream(path);
fos.write(classFile);
fos.flush();
System.out.println("代理类class文件写入成功");
}catch (Exception e) {
System.out.println("写文件错误");
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.Person;
public final class $Proxy0 extends Proxy implements Person
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
/**
*注意这里是生成代理类的构造方法,方法参数为InvocationHandler类型,看到这,是不是就有点明白
*为何代理对象调用方法都是执行InvocationHandler中的invoke方法,而InvocationHandler又持有一个
*被代理对象的实例,就可以去调用真正的对象实例。
*/
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
//这个静态块本来是在最后的,我把它拿到前面来,方便描述
static
{
try
{
//看看这儿静态块儿里面的住giveTask通过反射得到的名字m3,其他的先不管
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("proxy.Person").getMethod("giveTask", 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());
}
}
/**
*
*这里调用代理对象的giveMoney方法,直接就调用了InvocationHandler中的invoke方法,并把m3传了进去。
*this.h.invoke(this, m3, null);我们可以对将InvocationHandler看做一个中介类,中介类持有一个被代理对象,在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。
*/
public final void giveTask()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
}
4. 部分源码解析
aop创建代理的源码分析
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 1.创建proxyFactory,proxy的生产主要就是在proxyFactory做的
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 2.将当前bean适合的advice,重新封装下,封装为Advisor类,然后添加到ProxyFactory中
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 3.调用getProxy获取bean对应的proxy
return proxyFactory.getProxy(getProxyClassLoader());
}
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
// createAopProxy()方法就是决定究竟创建何种类型的proxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 关键方法createAopProxy()
return getAopProxyFactory().createAopProxy(this);
}
// createAopProxy()
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 1.config.isOptimize()是否使用优化的代理策略,目前使用与CGLIB
// config.isProxyTargetClass() 是否目标类本身被代理而不是目标类的接口
// hasNoUserSuppliedProxyInterfaces()是否存在代理接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
// 2.如果目标类是接口类(目标对象实现了接口),则直接使用JDKproxy
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 3.其他情况则使用CGLIBproxy
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable// JdkDynamicAopProxy类结构,由此可知,其实现了InvocationHandler,则必定有invoke方法,来被调用,也就是用户调用bean相关方法时,此invoke()被真正调用
// getProxy()
public Object getProxy(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);
// JDK proxy 动态代理的标准用法
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//使用了JDK动态代理模式,真正的方法执行在invoke()方法里,看到这里在想一下上面动态代理的例子,是不是就完全明白Spring源码实现动态代理的原理了。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class<?> targetClass = null;
Object target = null;
try {
// 1.以下的几个判断,主要是为了判断method是否为equals、hashCode等Object的方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// May be null. Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 2.获取当前bean被拦截方法链表
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 3.如果为空,则直接调用target的method
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
// 4.不为空,则逐一调用chain中的每一个拦截方法的proceed,这里的一系列执行的原因以及proceed执行的内容,我 在这里就不详细讲了,大家感兴趣可以自己去研读哈
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
...
return retVal;
}
}
}
。同时标星(置顶)本公众号可以第一时间<今天你面试了吗>系列博文推送。
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
相关文章
暂无评论...