跟蹤spring aop的實現
aop核心概念介紹
-
什麼是切面編程
在運行時,動態地將代碼切入到類的指定方法、指定位置上的編程思想就是面向切面編程。 -
Aspect(切面)
什麼是切面呢?切面這個詞感覺還是挺抽象的,咱們可能知道點構成線,線構成面的數據話術。但是在編程語言中如何體現這個面呢?我的理解是“在程序中切面是由切入點和在切入點的表現的行爲構成”。給個在spring中定義切面的例子如下:
<bean id="advice" class="com.im.sky.spring.aspect.GenericAdvice" />
<aop:config>
<aop:aspect id="aspect1" ref="advice">
<aop:pointcut id="p1" expression="execution(* com.im.sky.spring.bean.People.say(..))" />
<aop:before pointcut-ref="p1" method="before" />
</aop:aspect>
其中aop:aspect表示的就是一個切面,而aop:pointcut表示的是具體的切入點,即哪些類的哪些放到會被這個切面切到。aop:before表示的就是在切入點的哪一個位置執行什麼行爲。
-
crosscutting concerns(橫切關注點)
在實現業務的同時,可能會在代碼邏輯中加入日誌、參數校驗、安全檢查,這些通用的操作在aop中就叫做橫切關注點,因爲這類代碼是可以通用的,可以進行抽離,通過藉助於aop,可能將此類代碼和傳統的業務代碼就行解耦。 -
Advice
在切入點的具體實現,就稱之爲Advice,正如spring中定義的aop:before、aop:after處進行的行爲等。 -
JoinPoint
Advice在業務代碼執行時加入業務流程的點或者時機稱之爲JoinPoint,目前Spring只支持方法級別,但可以在方法的不同時機加入,比如調用方法之前、之後、返回之後、返回失敗時。 -
Pointcut(切入點)
Pointcut可以看做是JoinPoint的一個子集,對於每一個方法都會有一些切入的時機,但是呢,你可能只想切入你關注的一些方法,這些方法稱之爲切入點。
Spring中的aop
aop的實現原理還是藉助於動態代理實現的,而目前就是使用JDK動態代理和Cglib動態代理,當一個類實現接口時纔可以使用JDK動態代理,而Cglib不受此限制。
步驟一:定義spring aop配置
<bean id="advice" class="com.im.sky.spring.aspect.GenericAdvice" />
<aop:config>
<aop:aspect id="aspect1" ref="advice">
<aop:pointcut id="p1" expression="execution(* com.im.sky.spring.bean.People.say(..))" />
<aop:before pointcut-ref="p1" method="before" />
</aop:aspect>
步驟二:定義基本類
People類
public class People {
private String name;
public void setName(String name) {
System.out.println("name:" + name);
this.name = name;
}
public void say() {
System.out.println("說人話");
}
public void cry() {
System.out.println("痛苦纔會哭");
}
}
advice類
public class GenericAdvice {
public void before() {
System.out.println("before advice");
}
public void after() {
System.out.println("after advice");
}
public void iReturn() {
System.out.println("return advice");
}
public void throwsError() {
System.out.println("throws advice");
}
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("around advice for before");
Object o = pjp.proceed(pjp.getArgs());
System.out.println("around advice for after");
return o;
}
}
執行類Main
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
People people = context.getBean(People.class);
people.say();
}
}
spring中核心類:AbstractAutoProxyCreator
protected Object createProxy(
Class<?> beanClass, String beanName, 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()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
// 設置目標類,就是上面定義的People的實例(在spring配置文件中定義了一個,沒有粘貼)
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//這裏是核心,內部會選擇是採用JDK動態代理還是CgLib動態代理
return proxyFactory.getProxy(getProxyClassLoader());
}
proxyFactory.getProxy(ClassLoader loader)源碼
public Object getProxy(ClassLoader classLoader) {
// 下面看看如何構建aop代理對象的
return createAopProxy().getProxy(classLoader);
}
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.");
}
// 如果目標類是接口或者本身就是一個代理類纔會採用JDK動態代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 這裏內部用的就是Cglib動態代理
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
當選擇具體採用哪種代理方式後,就會調用getProxy構成具體的目標類的代理類對象。
JDK動態代理構建目標類代理對象源碼:
public Object getProxy(ClassLoader classLoader) {
if (logger.isDebugEnabled()) {
logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
}
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
Cglib動態代理構建目標類代理對象源碼:
public Object getProxy(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 ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + 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);
}
}
protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
return (this.constructorArgs != null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}
怎麼說呢,spring中的代碼還是很龐大的,如果想仔細的瞭解,就debug進入跟蹤一下吧,我這個寫的也是很少的一部分,中間還涉及預處理等很多東西。