Spring AOP理解

一、基础理解

        Spring AOP,即面向切面思想。使用切面来处理一些问题需要考虑:从哪里进行切入、在什么时候切入以及切面增加什么行为。整个AOP体系可以梳理为下图:

其中设计到的常用术语包括:

  • 连接点:类里面可以被增强的方法。
  • 切入点:类里面真正被增强的方法。
  • 通知:实际增强的逻辑部分,包括前置、后置、环绕、异常、最终通知
  • 切面:将通知应用到切入点的过程

二、基础原理解读

        Spring AOP的原理总结来说,就是动态代理。采用代理模式,生成一个个代理类,然后替换掉真是实现类来对外提供服务。Spring AOP就是通过getBean()方法返回代理类的实例。该代理类是Spring采用JDK Proxy或CGLIB动态生成的。

1、JDK动态代理

介绍:

        Spring默认使用JDK的动态代理实现AOP,类如果实现了接口,Spring就会使用这种方式实现动态代理。JDK实现动态代理需要两个组件,首先第一个就是InvocationHandler接口。我们在使用JDK的动态代理时,需要编写一个类,去实现这个接口,然后重写invoke方法,这个方法其实就是我们提供的代理方法。然后JDK动态代理需要使用的第二个组件就是Proxy这个类,我们可以通过这个类的newProxyInstance方法,返回一个代理对象。生成的代理类实现了原来那个类的所有接口,并对接口的方法进行了代理,我们通过代理对象调用这些方法时,底层将通过反射,调用我们实现的invoke方法。

优点:

  • JDK动态代理是JDK原生的,不需要任何依赖即可使用;
  • 通过反射机制生成代理类的速度要比CGLib操作字节码生成代理类的速度更快;

缺点:

  • 如果要使用JDK动态代理,被代理的类必须实现了接口,否则无法代理;
  • JDK动态代理无法为没有在接口中定义的方法实现代理,假设我们有一个实现了接口的类,我们为它的一个不属于接口中的方法配置了切面,Spring仍然会使用JDK的动态代理,但是由于配置了切面的方法不属于接口,为这个方法配置的切面将不会被织入。
  • JDK动态代理执行代理方法时,需要通过反射机制进行回调,此时方法执行的效率比较低;

2、CGLib动态代理

介绍:

        JDK的动态代理存在限制,那就是被代理的类必须是一个实现了接口的类,代理类需要实现相同的接口,代理接口中声明的方法。若需要代理的类没有实现接口,此时JDK的动态代理将没有办法使用,Spring就会使用CGLib的动态代理来生成代理对象。CGLib直接操作字节码,生成类的子类,重写类的方法完成代理。

优点:

  • 使用CGLib代理的类,不需要实现接口,因为CGLib生成的代理类是直接继承自需要被代理的类;
  • CGLib生成的代理类是原来那个类的子类,这就意味着这个代理类可以为原来那个类中,所有能够被子类重写的方法进行代理;
  • CGLib生成的代理类,和我们自己编写并编译的类没有太大区别,对方法的调用和直接调用普通类的方式一致,所以CGLib执行代理方法的效率要高于JDK的动态代理;

缺点:

  • 由于CGLib的代理类使用的是继承,这意味着如果需要被代理的类是一个final类,则无法使用CGLib代理;
  • 由于CGLib实现代理方法的方式是重写父类的方法,所以无法对final方法,或者private方法进行代理,因为子类无法重写这些方法;
  • CGLib生成代理类的方式是通过操作字节码,这种方式生成代理类的速度要比JDK通过反射生成代理类的速度更慢;

(一)Spring AOP生效方式

        Spring AOP的关键类就是DefaultAdvisorAutoProxyCreator。该类能自动将所有的advisor生效。通过查看该类的继承结构,惊喜地发现,最后居然是BeanPostProcessor。

public interface BeanPostProcessor {
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}

        上面是BeanPostProcessor的源码。其两个方法分别在init-method的前后得到执行。体现在Spring IOC中如下所示:

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// ...
		if (instanceWrapper == null) {
            // 1、创建实例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// ...
		try {
            // 2、装载属性
			populateBean(beanName, mbd, instanceWrapper);
            // 3、初始化
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		// ...
	}

        在AbstractAutowireCapableBeanFactory类中,对refresh()的最后一步,初始化所有的Singleton beans时,在第三步——执行bean初始化方法中,调用BeanPostProcessor的两个方法,来执行增强策略。

	protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		// ...
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // 执行BeanPostProcessor的postProcessBeforeInitialization()
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // 调用bean配置中的init-method="xxx"
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
            // 执行BeanPostProcessor的postProcessAfterInitialization()
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}

		return wrappedBean;
	}

(二)复写BeanPostProcessor的方法

        知道Spring AOP在哪里生效了,现在需要知道的就是如何完成的代理增强。通过查看DefaultAdvisorAutoProxyCreator的代理结构,从AbstractAutoProxyCreator中找到了对BeanPostProcessor两个方法的复写。

	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
		Object cacheKey = getCacheKey(beanClass, beanName);

		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// TargetSource——用于封装真实实现类的信息
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            // 创建代理
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}
    
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
		if (bean != null) {
			Object cacheKey = getCacheKey(bean.getClass(), beanName);
			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
				return wrapIfNecessary(bean, beanName, cacheKey);
			}
		}
		return bean;
	}

	protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		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;
		}

		// 返回匹配到的可以拦截当前bean的所有advisor、Advice、interceptor
		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;
	}

        通过上述代码,不论是前置增强,还是后置增强,最主要的过程就是创建代理——createProxy()

	// specificInterceptors:携带了所有的advisors;targetSource:携带了真实实现类的信息
    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 proxyFactory = new ProxyFactory();
		proxyFactory.copyFrom(this);

        // 设定动态代理方式:
        // 配置方式为proxy-target-class属性,默认为false,表示使用JDK动态代理;如果设为true,代表使用CGLIB
        // 如果使用CGLIB,增加以下逻辑
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

        // 返回匹配了当前bean的advisors数组
		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());
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值