spring-aop 扩展代理

前言

如果把《spring-beans核心容器》比较树干,spring-aop则是其树枝。使其在固定的生命周期之外拥有不一样的分枝。

AOP论述

spring aop的配置可以通过xml文件来进行,大概有四种方式:

  1. 配置ProxyFactoryBean,显式地设置advisors, advice, target等
  2. 配置AutoProxyCreator,这种方式下,还是如以前一样使用定义的bean,但是从容器中获得的其实已经是代理对象
  3. 通过<aop: config>来配置
  4. 通过<aop: aspectj-autoproxy>来配置,使用AspectJ的注解来标识通知及切入点

1,2方式是基于《浅谈AOP》的 aop alliance规范
3,4方式则是使用了AspectJ规范

基于ProxyFactoryBean的AOP

以下是其配置方式(省略部分代码)

<bean id="admin" class="entity.AdminUser" autowire="byType">
  <property name="username" value="eeeerrrr"></property>
</bean>
    
<bean id="aspect" class="entity.MyAspect"></bean>

<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="adminProxy">
    <property name="target" ref="admin"></property>
    <property name="interceptorNames" value="aspect"></property>
    <property name="proxyTargetClass" value="true"></property>
</bean>
public class MyAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("方法被调用["+methodInvocation.getMethod().getName() + "]");
        return methodInvocation.proceed();
    }
}

Resource resource = new ClassPathResource("spring-aop.xml");

//创建bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

/解析配置,并注册bean到工厂中
BeanDefinitionReader context=new XmlBeanDefinitionReader(factory);
context.loadBeanDefinitions(resource);

//从工厂中取出对象
AdminUser user = (AdminUser) factory.getBean("admin");
System.out.println(user.getUsername());

//符合FactoryBean的特性,取到了原对象
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) factory.getBean("&adminProxy");
System.out.println(proxyFactoryBean.getClass());

在这里插入图片描述

TargetClassAware

提供被代理对象的类型

//提供代理类的类型
Class<?> getTargetClass();
Advised

获取代理的配置信息

//冻结配置,冻结后配置都走缓存。
boolean isFrozen();

//是否采用继承类代理 	 	
boolean isProxyTargetClass();

//被代理对象所实现的接口集
Class<?>[] getProxiedInterfaces();

//是否被代理对象所实现的接口
boolean isInterfaceProxied(Class<?> intf);

//获取被代理对象
TargetSource getTargetSource();

//是否爆露代理对象
//如果爆路,在执行真实方法前,会把代理对象放到ThreadLocal中, 真实方法中可取
//@see AopContext.setCurrentProxy(proxy)
boolean isExposeProxy();

//是否开启ClassFilter过滤功能,来过滤一些不想作用的切点
boolean isPreFiltered();

//查询所有的切点
Advisor[] getAdvisors();
ProxyConfig

代理的基本配置信息

//是否采用继承类代理 	
private boolean proxyTargetClass = false;
//是否系统自动选择代理
private boolean optimize = false;

//如果代理类继续Advised,是否爆露
//@see AopProxyUtils.completeProxiedInterfaces
boolean opaque = false;

//是否爆露代理对象
boolean exposeProxy = false;

//冻结配置,冻结后配置都走缓存。
private boolean frozen = false;

AdvisedSupport

扩展ProxyConfig对Advised的具体实现。

//被代理对象,默认为一空值
TargetSource targetSource = EMPTY_TARGET_SOURCE;

//是否开启ClassFilter过滤功能,来过滤一些不想作用的advisor
private boolean preFiltered = false;

//advisor获取策略,主要是根据一定规则筛选出advisor,例如preFiltered
AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

//缓存method-advisors的Map,不用重新根据规则计算advisor
private transient Map<MethodCacheKey, List<Object>> methodCache;

//被代理对象实现的接口	
private List<Class<?>> interfaces = new ArrayList<>();

//所有的切点
private List<Advisor> advisors = new ArrayList<>();

//advisors的数组缓存	
private Advisor[] advisorArray = new Advisor[0];

//根据对象的方法及class结合advisorChainFactory筛选出advisor
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass)
ProxyCreatorSupport

适配器,将代理配置,提供给代理工厂,创建代理。

//选择代理策略
//如果代理类不是接口且本身不是代理类且 proxyTargetClass 或者 optimize 或者 代理类没接口 选用继承
private AopProxyFactory aopProxyFactory;

//代理配置修改监听类
private final List<AdvisedSupportListener> listeners = new LinkedList();
ProxyFactoryBean

通过FactoryBean.getObject的方式,切入bean的生命周期。

public Object getObject() throws BeansException {
     //将设置的interceptorNames,转化成Advisor放进代理配置里面
	 initializeAdvisorChain();
	 return getSingletonInstance();
}

private synchronized Object getSingletonInstance() {
    //createAopProxy,根据代理配置创建代理对象工厂,cglib 还是 jdk proxy
    //getProxy 根据代理对象工厂,结合被代理对象,具体返回值
	this.singletonInstance = getProxy(createAopProxy());
	return this.singletonInstance;
}

基于AutoProxyCreator的AOP

以下是其配置方式(省略部分代码)

//引用配置文件
Resource resource = new ClassPathResource("spring-aop.xml");

//创建bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

//创建BeanPostProcessor加入factory
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("admin");
beanNameAutoProxyCreator.setInterceptorNames("aspect");
beanNameAutoProxyCreator.setBeanFactory(factory);
factory.addBeanPostProcessor(beanNameAutoProxyCreator);

//解析配置,并注册bean到工厂中
BeanDefinitionReader context=new XmlBeanDefinitionReader(factory);
context.loadBeanDefinitions(resource);

//从工厂中取出对象
AdminUser user = (AdminUser) factory.getBean("admin");
System.out.println(user.getUsername());

在这里插入图片描述

ProxyProcessorSupport

在ProxyConfig的基础上, 增加processor的order配置,容器的加载配置。

//processor的顺序配置
private int order = Ordered.LOWEST_PRECEDENCE;
//加载器配置
private ClassLoader proxyClassLoader = ClassUtils.getDefaultClassLoader();
//是否可自定义加载器
private boolean classLoaderConfigured = false;
AbstractAutoProxyCreator

通过BeanPostProcessor.postProcessBeforeInstantiation的方式,切入bean的生命周期。

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
        //获取被代理对象
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		//抽象方法,根据具体实现返回代理的接口
		//为null则表示不代理
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
	    Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
		return proxy;
}


protected Object createProxy(Class<?> beanClass, String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
        
        //创建ProxyFactory,相当于ProxyCreatorSupport
		ProxyFactory proxyFactory = new ProxyFactory();
		//复制proxyConfig
		proxyFactory.copyFrom(this);
        
        //根据当前配置修改代理策略 
		if (!proxyFactory.isProxyTargetClass()) {
			if (shouldProxyTargetClass(beanClass, beanName)) {
				proxyFactory.setProxyTargetClass(true);
			}
			else {
				evaluateProxyInterfaces(beanClass, proxyFactory);
			}
		}

        //如果specificInterceptors为null返回空
        //如果不为null,将interceptorNames和specificInterceptors转为Advisor
		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());
	}
BeanNameAutoProxyCreator

制定根据beanName来决定是否代理

protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
         
		if (this.beanNames != null) {
		    //名称匹配还在别名匹配
			for (String mappedName : this.beanNames) {
				if (FactoryBean.class.isAssignableFrom(beanClass)) {
					if (!mappedName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
						continue;
					}
					mappedName = mappedName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
				}
				if (isMatch(beanName, mappedName)) {
					return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
				}
				BeanFactory beanFactory = getBeanFactory();
				if (beanFactory != null) {
					String[] aliases = beanFactory.getAliases(beanName);
					for (String alias : aliases) {
						if (isMatch(alias, mappedName)) {
							return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
						}
					}
				}
			}
		}
		//beanNames为空直接代理
		return DO_NOT_PROXY;
	}
基于config的AOP

因为其引用了AspectJ规范,所以要引入aspectjweaver。以下是其配置方式(省略部分代码)

    <bean id="aspect" class="entity.MyAspect2"></bean>

    <aop:config>
        <!--声明一个切点,用来切方法 -->
        <aop:pointcut id="myPoint" expression="execution(* *.*.*(..))"/>
        <!--声明一个切面 用来增强方法 -->
        <aop:aspect id="aspect" ref="aspect" order="1" >
            <aop:before  method="myBefore" pointcut-ref="myPoint"></aop:before>
            <aop:after method="myAfter" pointcut-ref="myPoint"  ></aop:after>
            <aop:after-returning method="myAfterReturning" returning="result1" pointcut-ref="myPoint"></aop:after-returning>
            <aop:around method="myAround" pointcut-ref="myPoint"></aop:around>
            <aop:after-throwing method="myThrow" pointcut-ref="myPoint" throwing="throwable"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
        //引用配置文件
        Resource resource = new ClassPathResource("spring-aop.xml");

        //创建bean工厂
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

        //解析配置,并注册bean到工厂中
        //解析aop:config时
        // 1.会注册  AspectJAwareAdvisorAutoProxyCreator 的BeanDefinition
        // 2.解析 aop:before 注册 AspectJPointcutAdvisor#0 的BeanDefinition
        //@see ConfigBeanDefinitionParser
        //@see AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary
        BeanDefinitionReader context=new XmlBeanDefinitionReader(factory);
        context.loadBeanDefinitions(resource);

        //初始化 aspectJAwareAdvisorAutoProxyCreator 并作为 BeanPostProcessor 加入
        AspectJAwareAdvisorAutoProxyCreator aspectJAwareAdvisorAutoProxyCreator = (AspectJAwareAdvisorAutoProxyCreator) factory.getBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
        factory.addBeanPostProcessor(aspectJAwareAdvisorAutoProxyCreator);

        //从工厂中取出对象
        AdminUser user = (AdminUser) factory.getBean("admin");
        System.out.println(user.getUsername());

在这里插入图片描述

AbstractAdvisorAutoProxyCreator

把配置文件解析出来的AspectJPointcutAdvisor实体化,并进行匹配。

//实现根据beanClass查找切面的功能
protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
}

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
        //从容器中找到Advisor的BeanDefinition并加载
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		//根据类,及poincut的ClassFilter及其它过渡Advisor
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
		//给继承类扩展使用
		extendAdvisors(eligibleAdvisors);
		if (!eligibleAdvisors.isEmpty()) {
		    //排序切面,根据Advisor的order属性
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}
		return eligibleAdvisors;
}
AspectJAwareAdvisorAutoProxyCreator

对AbstractAdvisorAutoProxyCreator的一些方法具体实现

//根据order属性排序
protected List<Advisor> sortAdvisors(List<Advisor> advisors)

基于aspectj-autoproxy的AOP

与aop:config实现原理差不多,借助于注解而已。最终作用在AnnotationAwareAspectJAutoProxyCreator。
在这里插入图片描述
详情介绍(略)。

AspectJ 和 spring AOP

  1. Spring AOP 只是用了AspectJ的规范而已,基实现还是基于JdkProxy 或者 cglib继承
  2. Spring AOP 只能作用在运行时,可 AspectJ 可作用在任意阶段更为灵活
  3. AspectJ 属于直接操作字节码,而Spring AOP不管是通过cglib的继承,还是JdkProxy,效率要明显慢于AspectJ
  4. Spring AOP 操作更简单方便

JdkProxy 和 CGLIB 的 例子

public class ProxyTest {

    static interface Car{
         void drive();
         void recharge();
    }

    static class ElectricCar implements Car {
        public void drive() {
            System.out.println("Electric Car is Moving silently...");
            this.recharge();
        }

        public void recharge() {
            System.out.println("Electric Car is Recharging...");
        }
    }

    static class MyMethodInterceptor implements InvocationHandler {

        private Object actor;

        public MyMethodInterceptor(Object actor) {
            this.actor = actor;
        }

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("Before: "+ method);
            Object ret = method.invoke(actor,args);
            System.out.println("After: "+method);
            return ret;
        }
    }

    public static void main(String[] args) throws Exception {
        ElectricCar car = new ElectricCar();
        Object obj = Proxy.newProxyInstance(ProxyTest.class.getClassLoader(),new Class[]{Car.class}, new MyMethodInterceptor(car));
        Method method = Car.class.getDeclaredMethod("drive");
        method.invoke(obj);
    }
}

public class CglibTest  {

    static class MyMethodInterceptor implements MethodInterceptor {
        public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
            System.out.println("Before: "+ method);
            Object object = proxy.invokeSuper(obj, arg);
            System.out.println("After: "+method);
            return object;
        }

    }

    static class ElectricCar  {
        public void drive() {
            System.out.println("Electric Car is Moving silently...");
            this.recharge();
        }

        public void recharge() {
            System.out.println("Electric Car is Recharging...");
        }
    }

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(ElectricCar.class);
        enhancer.setCallback(new MyMethodInterceptor());
        ElectricCar student = (ElectricCar)enhancer.create();
        student.drive();
    }
}

采用接口代理的进行了一次切面,调用drive
采用继承代理的进行了二次切面,调用drive

继承中this指的是父类自己。
从AOP层面证明了spring事务,使用接口代理时,在类中自己调用自己无效。

主要参考

SpringAop的三种配置方法:基于ProxyFactoryBean、基于AspectJ的xml,基于AspectJ的注解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值