栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring源码解析-4.AOP源码解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring源码解析-4.AOP源码解析

目录
  • 一、AOP是什么?
  • 二、Spring AOP简易使用(注解版)
  • 三、AOP实现原理介绍
  • 四、AOP入口(源码解析)


一、AOP是什么?

面向切面编程,作为面向对象的一种补充,将公共逻辑(事务管理、日志、缓存等)封装成切面,跟业务代码进行分离,可以减少系统的重复代码和降低模块之间的耦合度。切面就是那些与业务无关,但所有业务模块都会调用的公共逻辑。

二、Spring AOP简易使用(注解版)

1、定义一个切面类Aspect
即在声明的类上,增加@Aspect、@Component两个注解,在配置类上添加@EnableAspectJAutoProxy注解开启AOP。(Spring是需要手动添加@EnableAspectJAutoProxy注解进行集成的,而SpringBoot中使用自动装配的技术,可以不手动加这个注解就实现集成。)
切面类:

@Aspect
@Component
public class LklAspect {
}

配置类:

@ComponentScan("com.lkl")
@EnableAspectJAutoProxy
public class ContextConfig {
}

2、定义切点Pointcut
定义切点,并定义切点在那些地方执行,采用@Pointcut注解完成,如@Pointcut(public * com.xxx.xxx.* . **(…))。规则:修饰符(可以不写,但不能用 * )+返回类型+哪些包下的类+哪些方法+方法参数 *代表所有,"…"两个点代表参数不限。
自定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
    String value() default "";
}

切点方法:

@Aspect
@Component
public class LklAspect {
    
    @Pointcut("@annotation(com.lkl.aspect.anno.SysLog)")
    public void myPointcut() {}
 }

3、定义Advice通知
利用通知的5种注解@Before、@After、@AfterReturning、@AfterThrowing、@Around来完成在某些切点的增强动作,如@Before(“myPointcut()”),myPointcut为第二步定义的切点

代码如下:

@Aspect
@Component
public class LklAspect {

	@Before("execution(* com.lkl.service.*.create*(..))")
	public void before(JoinPoint joinPoint) {
		System.out.println("准备执行方法: " + joinPoint.getSignature().getName() + ", 参数列表:" + Arrays.toString(joinPoint.getArgs()));
	}


	@AfterReturning(value = "execution(* com.lkl.service.*.query*(..))", returning = "returnValue")
	public void afterReturning(JoinPoint point, Object returnValue) {
		System.out.println(point.getSignature().getName() + "方法返回:" + returnValue);
	}
}
三、AOP实现原理介绍

Spring AOP是通过动态代理实现的,代理模式,接口 + 真实实现类 + 代理类,其中 真实实现类 和 代理类 都要实现接口,实例化的时候要使用代理类。所以,Spring AOP 需要做的是生成这么一个代理类,然后替换掉真实实现类来对外提供服务。
替换的过程怎么理解呢?在 Spring IOC 容器中非常容易实现,就是在 getBean(…) 的时候返回的实际上是代理类的实例,而这个代理类我们自己没写代码,它是 Spring 采用 JDK Proxy 或 CGLIB 动态生成的。

getBean(…) 方法用于查找或实例化容器中的 bean,这也是为什么 Spring AOP 只能作用于 Spring 容器中的 bean 的原因,对于不是使用 IOC 容器管理的对象,Spring AOP 是无能为力的。

Aspect概念
Spring AOP 中主要概念理解:

  • aspect:切面,切面由切点和通知组成,即包括横切逻辑的定义也包括连接点的定义
  • pointcut:切点,每个类都拥有多个连接点,可以理解是连接点得集合
  • joinpoint:连接点,程序执行的某个特定位置,如某个方法调用前后等
  • weaving:织入,将增强添加到目标类的具体连接点的过程
  • advice:通知,是织入到目标类连接点上的一段代码,就是增强到什么地方?增强到什么内容?(五种通知类型)
  • target:目标对象,通知织入的目标类
  • aop Proxy:代理对象,即增强后产生的对象

JDK代理与CGLIB代理的区别

  • JDK动态代理实现接口,CGLIB动态继承思想
  • JDK动态代理(目标对象存在接口时)执行效率高于CGLIB
  • 如果对象有接口实现,选择JDK代理,如果没有接口实现选择CGLIB代理

JDK、CGLIB代码简易实现:

  • JDK动态代理:

接口:

public interface Subject {
    void doSomething();
}

真实实现类:

public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}

代理类:

public class JDKDynamicProxy implements InvocationHandler {

    private Object target;

    public JDKDynamicProxy(Object target) {
        this.target = target;
    }

    
    public  T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Do something before");
        Object result = method.invoke(target, args);
        System.out.println("Do something after");
        return result;
    }
}

测试:

public class Client {

    public static void main(String[] args) {

        RealSubject realSubject = new RealSubject();
        realSubject.doSomething();

		System.out.println("***********************");
        // jdk动态代理测试
        Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
        subject.doSomething();
    }
}

结果如下:

可以发现真实对象,运行还是原本的方法,使用动态代理生成的代理对象,则是增强后的方法。

  • CGLIB动态代理:

父类:

public class RealSubject {
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}

代理类:

public class CgLibProxy implements MethodInterceptor {

	Object target;

	public CgLibProxy(Object target) {
		this.target = target;
	}

	
	public Object getProxy() {
		//可以通过Enhancer对象中的create()方法可以去生成一个类,用于生成代理对象
		Enhancer enhancer = new Enhancer();
		//设置父类(将目标类作为代理类的父类)
		enhancer.setSuperclass(target.getClass());
		//设置拦截器(回调对象为本身对象)
		enhancer.setCallback(this);
		//生成一个代理类对象
		return enhancer.create();
	}

	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println("方法执行前的增强行为");
		Object result = method.invoke(target, objects);
		System.out.println("方法执行后的增强行为");
		return result;
	}
}

测试:

public class Test {
	public static void main(String[] args) {
		RealSubject realSubject = new RealSubject();
		realSubject.doSomething();

		System.out.println("***********************");
		RealSubject proxy = (RealSubject) new CgLibProxy(new RealSubject()).getProxy();
		proxy.doSomething();

	}
}

结果:

四、AOP入口(源码解析)
  • spring集成AspectJ AOP主要是@EnableAspectJAutoProxy注解的作用。
    该注解是一个复合注解,如下所示:

    @Import注解可以注入一个类到Spring容器当中,上述注解将AspectJAutoProxyRegistrar类注入到spring容器里。spring容器初始化时,执行加载和注册beanDefinition的时候,会使用该类的registerBeanDefinitions方法进行注册beanDefinition。也就来到了AspectJAutoProxyRegistrar中的registerBeanDefinitions方法。



该方法的作用就是将AnnotationAwareAspectJAutoProxyCreator注册到容器当中,这个类是Spring AOP的关键。此时Spring中就有了Aspect AOP的功能

  • 然后真正创建bean的方法doCreateBean(...)部分核心代码
	// 创建实例
	instanceWrapper = createBeanInstance(beanName, mbd, args);
	....
	// 依赖注入,主要为属性的依赖注入
	populateBean(beanName, mbd, instanceWrapper);
	// 1、bean执行Aware回调方法 2、执行 beanPostProcessor前置方法 
	// 3、执行类的初始化方法 4、执行beanPostProcessor后置方法
	exposedObject = initializeBean(beanName, exposedObject, mbd);
  • initializeBean(beanName, exposedObject, mbd)初始化bean
	// BeanPostProcessors 前置方法的调用
	wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);

	// 调用类的初始化方法
	invokeInitMethods(beanName, wrappedBean, mbd);

	// bean 后置方法调用,在这里有可能对bean进行代理
	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  • 后置处理
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
  • 动态代理入口

    方法如下,判断是否需要代理
	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
		    // 先从缓存中获取
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
			    //如果需要对该bean对象进行代理,返回代理对象
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}
  • wrapIfNecessary(bean, beanName, cacheKey)
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		//判断是否已经被代理
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		//不需要代理,或者配置了conditional跳过
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}

		// Create proxy if we have advice.
		//寻找切面
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			//放入缓存
			this.advisedBeans.put(cacheKey, Boolean.TRUE);
			//创建代理对象
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		//不需要代理
		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}
  • 创建代理对象 Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean))
	protected Object createProxy(Class beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {

		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
		}

		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

		if (proxyFactory.isProxyTargetClass()) {
			// Explicit handling of JDK proxy targets (for introduction advice scenarios)
			if (Proxy.isProxyClass(beanClass)) {
				// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
				for (Class ifc : beanClass.getInterfaces()) {
					proxyFactory.addInterface(ifc);
				}
			}
		}
		else {
			// No proxyTargetClass flag enforced, let's apply our default checks...
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
		proxyFactory.addAdvisors(advisors);
		proxyFactory.setTargetSource(targetSource);
		customizeProxyFactory(proxyFactory);

		proxyFactory.setFrozen(this.freezeProxy);
		if (advisorsPreFiltered()) {
			proxyFactory.setPreFiltered(true);
		}
        //获取代理对象
		return proxyFactory.getProxy(getProxyClassLoader());
	}
  • 最后调用方法,根据不同类型调用不同动态代理模式获取代理对象
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/967297.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号