Spring 的兩大核心,一是IOC,我們之前已經學習過,并且已經自己動手實現了一個,而令一個則是大名鼎鼎的 AOP,AOP的具體概念我就不介紹了,我們今天重點是要從源碼層面去看看 spring 的 AOP 是如何實現的。注意,今天樓主給大家分享的是 XML 配置AOP的方式,不是我們經常使用的注解方式,為什么呢?
有幾個原因:
- Spring AOP 在 2.0 版本之前都是使用的 XML 配置方式,封裝的層次相比注解要少,對于我們學習AOP是個很好的例子。
- 雖然現在是2017年,現在使用SpringBoot 都是使用注解了, 但是底層原理都是一樣的,只不過多了幾層封裝。當然,我們也是要去扒開它的源碼的。但不是今天。
- 樓主也還沒有分析注解方式的AOP。-_-|||
我們主要分為幾個步驟去理解:
- 查看源碼了解 spring AOP 的接口設計。Advice,PointCut,Advisor。
- 用一個最簡單的代碼例子 debug 追蹤源碼。
那么我們現看第一步:
1. Spring AOP 接口設計
1.1 PointCut (連接點,定義匹配哪些方法)
我們打開 Spring 的源碼,查看 PointCut 接口設計:
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
Pointcut TRUE = TruePointcut.INSTANCE;
}
該接口定義了2 個方法,一個成員變量。我們先看第一個方法, ClassFilter getClassFilter()
,該方法返回一個類過濾器,由于一個類可能會被多個代理類代理,于是Spring引入了責任鏈模式,另一個方法則是 MethodMatcher getMethodMatcher()
,表示返回一個方法匹配器,我們知道,AOP 的作用是代理方法,那么,Spirng 怎么知道代理哪些方法呢?必須通過某種方式來匹配方法的名稱來決定是否對該方法進行增強,這就是 MethodMatcher 的作用。還有要給默認的 Pointcut 實例,該實例對于任何方法的匹配結果都是返回 true。
我們關注一下 MethodMatcher 接口:
public interface MethodMatcher {
boolean matches(Method method, @Nullable Class<?> targetClass);
boolean isRuntime();
boolean matches(Method method, @Nullable Class<?> targetClass, Object... args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
該接口定義了靜態方法匹配器和動態方法匹配器。所謂靜態方法匹配器,它僅對方法名簽名(包括方法名和入參類型及順序)進行匹配;而動態方法匹配器,會在運行期檢查方法入參的值。靜態匹配僅會判別一次,而動態匹配因為每次調用方法的入參都可能不一樣,所以每次都必須判斷。一般情況下,動態匹配不常用。方法匹配器的類型由isRuntime()返回值決定,返回false表示是靜態方法匹配器,返回true表示是動態方法匹配器。
總的來說, PointCut 和 MethodMatcher 是依賴關系,定義了AOP應該匹配什么方法以及如何匹配。
1.2 Advice (通知,定義在鏈接點做什么)
注意,Advice 接口只是一個標識,什么也沒有定義,但是我們常用的幾個接口,比如 BeforeAdvice,AfterAdvice,都是繼承自它。我們關注一下 AfterAdvice 的子接口 AfterReturningAdvice :
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
該接口定義了一個方法,afterReturning,參數分別是返回值,目標方法,參數,目標方法類,在目標方法執行之后會回調該方法。那么我們就可以在該方法中執行我們的切面邏輯,BeforeAdvice 也是一樣的道理。
1.3 Advisor (通知器,將 Advice 和 PointCut 結合起來)
有了對目標方法的增強接口 Advice 和 如何匹配目標方法接口 PointCut 接口后,那么我們就需要用一個對象將他們結合起來,發揮AOP 的作用,所以Spring 設計了 Advisor(通知器),經過我們剛剛的描述,我們應該知道了,這個 Advisor 肯定依賴了 Advice 和 PointCut,我們看看接口設計:
public interface Advisor {
Advice EMPTY_ADVICE = new Advice() {};
Advice getAdvice();
boolean isPerInstance();
}
還有他的子接口:
public interface PointcutAdvisor extends Advisor {
Pointcut getPointcut();
}
最重要的兩個方法,getAdvice,getPointcut。和我們預想的基本一致。
接下來,我們可以停下來思考一下,現在有了這個東西,我們怎么實現面向切面編程;
- 首先我們需要告訴AOP在哪里進行切面。比如在某個類的方法前后進行切面。
- 告訴AOP 切面之后做什么,也就是說,我們知道了在哪里進行切面,那么我們也該讓spring知道在切點處做什么。
- 我們知道,Spring AOP 的底層實現是動態代理(不管是JDK還是Cglib),那么就需要一個代理對象,那么如何生成呢?
接下來,我們將通過代碼的方式,解答這三個疑惑。
2. 從一個簡單的AOP例子
首先,我們需要實現剛剛我們說的3個接口,還有一個目標類,還要一個配置文件。一個一個來。
2.1. Pointcut 接口實現
package test;
import java.lang.reflect.Method;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
public class TestPointcut implements Pointcut {
@Override
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
public boolean matches(Method method, Class<?> targetClass, Object[] args) {
if (method.getName().equals("test")) {
return true;
}
return false;
}
public boolean matches(Method method, Class<?> targetClass) {
if (method.getName().equals("test")) {
return true;
}
return false;
}
public boolean isRuntime() {
return true;
}
};
}
}
我們如何定義匹配?只要方法名稱是test則對該方法進行增強或者說攔截。
2.2 AfterAdvice 實現
package test;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class TestAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println(
"after " + target.getClass().getSimpleName() + "." + method.getName() + "()");
}
}
我們在方法執行完畢后打印該方法的名稱和該目標類的名稱。這就是我們做的簡單增強。
2.3 Advisor 通知器的實現
package test;
import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
/**
* 通知器
*/
public class TestAdvisor implements PointcutAdvisor {
/**
* 獲取通知處理邏輯
*/
@Override
public Advice getAdvice() {
return new TestAfterAdvice();
}
@Override
public boolean isPerInstance() {
return false;
}
/**
* 獲取切入點
*/
@Override
public Pointcut getPointcut() {
return new TestPointcut();
}
}
我們實現了 PointcutAdvisor 接口,返回我們剛才定義的兩個類。完成了他們的組合。
2.4 定義目標類 Targe
package test;
public class TestTarget {
public void test() {
System.out.println("target.test()");
}
public void test2() {
System.out.println("target.test2()");
}
}
該目標的實現和簡單,就是2個方法,分別打印自己的名字。
2.5 定義XML 配置文件
<?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-2.5.xsd">
<bean id="testAdvisor" class="test.TestAdvisor"></bean>
<bean id="testTarget" class="test.TestTarget"></bean>
<bean id="testAOP" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetName">
<value>testTarget</value>
</property>
<property name="interceptorNames">
<list>
<value>testAdvisor</value>
</list>
</property>
</bean>
</beans>
可以看到,我們定義了3個bean,上面兩個是我們剛剛定義的,下面一個我們要好好說說,ProxyFactoryBean 是一個什么東西呢?首先他是一個 FactoryBean,我們在學習 IOC 的時候知道, FactoryBean 是Spring 留給我們擴展用的,實現該接口的類可以自定類的各種功能。ProxyFactoryBean 當然也實現了自己的很多自定義功能。ProxyFactoryBean 也是Spring IOC 環境中創建AOP 應用的底層方法,Spring 正式通過它來實現對AOP的封裝。這樣我們更加接近Spring的底層設計。而該類需要注入兩個屬性一個目標類,一個攔截類,ProxyFactoryBean 會生成一個動態代理類來完成對目標方法的攔截。
2.6 測試類
package test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class TestAOP {
public static void main(String[] args) {
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(
"spring-context/src/test/java/test/beans.xml");
TestTarget target = (TestTarget) applicationContext.getBean("testAOP");
target.test();
System.out.println("----------------");
target.test2();
}
}
我們看看運行結果:
可以看到結果符合我們的預期,因為我們只配置了在test名稱的方法之后打印該方法的名稱和該目標類的名稱,而test2 則沒有配置,因此也就沒有打印。
那么是怎么實現的呢? 讓我們進入源碼看個究竟。
3. 深入 AOP 源碼實現
首先我們看看我們的測試代碼,我們第一句代碼是IOC 初始化,這個我們就不講了,我們在之前的文章已經分析過,我們重點看第二行代碼,我們debug 到第三行,看看第二行返回的對象是什么?
我們看到,第二行從IOC容器中取出的是一個Cglib 生成的代理對象,也既是繼承了我們TestTarge 類的實例,而不是我們在 XML 中定義的 ProxyFactoryBean 對象,也就是說, FactoryBean 確實能夠在IOC容器中做一些定制化。那么我們就很好奇,這個代理對象是怎么生成的。我們從第二行代碼開始進入。
首先進入抽象類 AbstractApplicationContext 的getBean 方法,從容器或獲取 Bean,再調用 doGetBean 方法,這個方法我們很熟悉,因為再之前的IOC過程中,我們看了好多遍了,我們重點看看該方法實現:
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();// 設置依賴關系
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);// 遞歸
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {// 創建bean
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);// 獲取實例
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
該方法會進入到第一個if塊中的 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null)
方法中,而 getObjectForBeanInstance 方法則會先判斷緩存是否存在,如果不存在,則進入父類的 getObjectForBeanInstance 方法,我們看看該方法實現:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
首先判斷是否是 Bean 引用類型并且是否是 Factory 類型,很面向不是Bean 引用類型(Bean引用類型指的是IOC在解析XML文件 的時候,會有 ref 屬性,而這個ref 對象還沒有實例化,則暫時創建一個Bean引用類型的實例,用于在依賴注入的時候判斷是否是Bean的屬性類型,如果是,則從容器中取出,如果不是,則是基本類型,就直接賦值),然后進入下面的if判斷,很明顯會直接跳過。進入下面的 getCachedObjectForFactoryBean(beanName) 方法,從緩存中取出,很明顯,第一次肯定返回null,繼續向下,進入if塊,重點在 object = getObjectFromFactoryBean(factory, beanName, !synthetic) 方法,我們進入該方法查看:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, object);
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
該方法還是先重緩存中取出,然后進入 doGetObjectFromFactoryBean(factory, beanName) 方法,我們看看該方法:
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
factory.getObject(), acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
object = factory.getObject();// 此處調用 ProxyFactoryBean
}
}
catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
該方法會直接進入 object = factory.getObject() 行,也就是 ProxyFactoryBean 的 getObject 方法,還記得我們說過,Spring 允許我們從寫 getObject 方法來實現特定邏輯嗎? 我們看看該方法實現:
public Object getObject() throws BeansException {
initializeAdvisorChain();// 為代理對象配置Advisor鏈
if (isSingleton()) {// 單例
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}// 非單例
return newPrototypeInstance();
}
}
該方法很重要,首先初始化通知器鏈,然后獲取單例,這里返回的就是我們最初看到的Cglib 代理。這里的初始化過濾器鏈的重要作用就是將連接起來,基本實現就是循環我們在配置文件中配置的通知器,按照鏈表的方式連接起來。具體代碼各位有興趣自己去看,今天這個不是重點。首先判斷是否是單例,然后我們著重關注下面的方法 getSingletonInstance();
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
該方法是同步方法,防止并發錯誤,因為有共享變量。首先返回一個包裝過的目標對象,然后是否含有接口,我們的目標類沒有接口,進入if塊,從目標類中取出所有接口并設置接口。很明顯,并沒有什么作用,然后向下走,重要的一行是 getProxy(createAopProxy())
,先創建AOP,再獲取代理。我們先看 crateAopProxy。
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
該方法返回一個AopProxy 類型的實例,我們看看該接口:
public interface AopProxy {
Object getProxy();
Object getProxy(@Nullable ClassLoader classLoader);
}
該接口定義了兩個重載方法,我們看看它有哪些實現:
這是該接口的繼承圖,分別是 JdkDynamicAopProxy 動態代理和 CglibAopProxy 代理。而 JdkDynamicAopProxy 實現了 InvocationHandler 接口,如果熟悉Java 動態代理,應該和熟悉該接口,實現了該接口的類并實現invoke方法,再代理類調用的時候,會回調該方法。實現動態代理。
我們繼續看 createAopProxy 方法,該方法主要邏輯是創建一個AOP 工廠,默認工廠是 DefaultAopProxyFactory,該類的 createAopProxy 方法則根據 ProxyFactoryBean 的一些屬性來決定創建哪種代理:
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);
}
}
只要滿足三個條件中的其中一個就,我們看最后一個判斷,是否含有接口,沒有則返回ture,也就是說,如果目標類含有接口,則創建Cglib 代理,否則則是JDK代理。最終創建了一個 ObjenesisCglibAopProxy 代理。
我們回到 ProxyFactoryBean 類的 getProxy 方法,當 createAopProxy 返回一個Cglib 代理的后,則調用 getProxy 方法獲取一個代理對象,我們看看該方法實現:
@Override
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
proxySuperClass = rootClass.getSuperclass();
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// Validate the class, writing log messages as necessary.
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB Enhancer...
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create a proxy instance.
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of class [" +
this.advised.getTargetClass() + "]: " +
"Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
該方法基本上就是使用了Cglib 的庫的一些API最后通過字節碼生成代理類,比如 Enhancer 增強器,樓主對ASM 和 Cglib 也不是很熟悉,下次有機會再看詳細實現。總之,我們已經知道了Spring 是如何生成代理對象的,主要的通過 ProxyFactoryBean 來實現。
最后,返回代理類,執行代理類的方法。完成切面編程。
4. 總結
我們通過一個簡單的例子debug spring 源碼,了解了通過配置文件方式配置AOP的詳細過程,其中起最重要作用的還是 ProxyFactoryBean ,在定制化Bena的過程中起到了很大的作用,也提醒了我們,如果想在Spring的bean容器實現一些特別的功能,可以實現 FactoryBean 接口,自定義自己的需要Bean。還有一點,今天我們學習的例子是通過XML方式,而這個方式確實有些古老,雖然不妨礙我們學習 AOP 的精髓,但我們還是希望能夠深入了解基于注解的AOP的具體實現,也許實現源碼相似,但我們還是想知道到底有哪些不同,最起碼樓主在剛剛的調試中發現最新的SpringBoot的AOP不是基于ProxyFactroyBean實現的。但不要灰心,原理都是相同的。剩下的就是我們自己去挖掘。
good luck!!!