Spring AOP原理浅析

AOP(面向切面编程)是一种编程思想。在实际开发中我们可以通过Spring AOP对业务进行增强,即在不改变原来业务基本架构和逻辑的基础上对某部分业务进行扩展。

例如,我们可以通过Spring AOP对业务中的CRUD操作添加日志,记录一些细节,如记录进行查询操作的时间和ip地址等信息。Spring AOP底层是基于代理来实现的,Jdk动态代理和Cglib动态代理。动态代理在前面做过简要分析。这里主要介绍两者的不同点:

如果目标对象实现了某一接口,则一般通过Jdk动态代理方式来生成代理对象。如果目标对象没有实现接口,则只能采用Cglib动态代理。Cglib动态代理不是Java的原生包提供的,需要引入外部包。(maven方式)

<dependency>
         <groupId>cglib</groupId>
         <artifactId>cglib</artifactId>
         <version>2.2.2</version>
 </dependency>

而Spring AOP的底层实现正式基于这两种代理方式,下面做简要分析:

接口

public interface TargetInteface {
    void method1();
    void method2();
    int method3(Integer i);
}

目标对象,实现了接口,则底层采用Jdk动态代理

public class Target implements TargetInteface{

  
    public void method1() {
        System.out.println("method1 running ...");
    }

    public void method2() {
        System.out.println("method2 running ...");
    }

    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

Spring AOP的xml配置文件 ,注意targetProxy这个bean,它是通过ProxyFactoryBean通过代理模式生成的代理对象。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--将Target目标类注入IOC容器-->
    <bean id="target" class="com.heaboy.aopdemo.aop.Target"/>
    
    <!--将对原业务逻辑的增强部分注入IOC容器-->
    <bean id="targetAdvice" class="com.heaboy.aopdemo.aop.TargetAdvice"/>

    <!--通过ProxyFactoryBean生成的代理对象-->
    <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="target"/> <!--被代理的类-->
        <property name="interceptorNames" value="targetAdvice"/>  <!--如果用多种增强方式,value的值使用逗号(,)分割-->
        <property name="proxyTargetClass" value="true"/>
        <property name="interfaces" value="com.heaboy.aopdemo.aop.TargetInteface"/>  <!--target实现的接口-->
    </bean>
</beans>

下面我们进入源码做简要分析:

以ProxyFactoryBean作为入口

 ProxyFactoryBean类中有一个getObject()方法,

 

 initializeAdvisorChain();方法用来存放通知,即增强的业务。然后判断是单例实例还是原型实例分别进入不同分支,但最终它们都会调用getProxy()方法。

@Override
	@Nullable
	public Object getObject() throws BeansException {
		initializeAdvisorChain();
		if (isSingleton()) {
			return getSingletonInstance();
		}
		else {
			if (this.targetName == null) {
				logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
						"Enable prototype proxies by setting the 'targetName' property.");
			}
			return newPrototypeInstance();
		}
	}

如下:

单例:getSingletonInstance()

this.singletonInstance = getProxy(createAopProxy());

原型: newPrototypeInstance()

return getProxy(copy.createAopProxy());

createAopProxy()用来确定生成代理对象的方式,即Jdk代理还是Cglib代理。

protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}

代理工厂接口    AopProxyFactory

public interface AopProxyFactory {

	/**
	 * Create an {@link AopProxy} for the given AOP configuration.
	 * @param config the AOP configuration in the form of an
	 * AdvisedSupport object
	 * @return the corresponding AOP proxy
	 * @throws AopConfigException if the configuration is invalid
	 */
	AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;

}

 DefaultAopProxyFactory为AopProxyFactory唯一的实现类,该类中的createAopProxy()方法用来判断代理方式并返回不同的代理对象。

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		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.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}


}

getProxy()中有一个参数AopProxy,且它的类型由createAopProxy()返回的对象类型确定,而createAopProxy()只会返回JdkDynamicAopProxy或ObjenesisCglibAopProxy类型的对象。

protected Object getProxy(AopProxy aopProxy) {
		return aopProxy.getProxy(this.proxyClassLoader);
	}

AopProxy同时是一个接口,其中有两个抽象方法。 且具有两个实现类,通过AopProxy的具体类型去实现不同的实现类,这是多态的方式。

 AopProxy有两个实现类如下,正是Jdk动态代理方式和Cglib动态代理方式。,getProxy()方法会通过它们实现接口并实现接口的两个方法获取代理对象。

 我们以JdkDynamicAopProxy做简要分析:Jdk动态代理必须要实现InvocationHander接口,如下

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {


..................




@Override
	public Object getProxy() {
		return getProxy(ClassUtils.getDefaultClassLoader());
	}




	@Override
	public Object getProxy(@Nullable ClassLoader classLoader) {
		if (logger.isTraceEnabled()) {
			logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
		}
		Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}





..................

}

分析两个方法,如果没有传来类加载器,使用ClassUtils中默认的类加载器。如果有,则使用传来的类加载器。最终通过

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

生成代理对象并返回。

这个图简单明了表示上述过程:图片连接https://blog.csdn.net/xc123_java/article/details/90448446

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值