近期打算把Spring源碼系統(tǒng)性的刷一遍,話不多說,那就先從Aop開始吧~~~
一、動態(tài)代理:
1颅湘、cglib的動態(tài)代理
UserService target =new UserService();
// 通過cglib技術
Enhancer enhancer =new Enhancer();
enhancer.setSuperclass(UserService.class);
// 定義額外邏輯,也就是代理邏輯
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
@Override
public Objectintercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {
System.out.println("before...");
Object result = methodProxy.invoke(target, objects);
System.out.println("after...");
return result;
}
}});
// 動態(tài)代理所創(chuàng)建出來的UserService對象
UserService userService = (UserService) enhancer.create();
//System.out.println(userService);
// 執(zhí)行這個userService的test方法時栗精,就會額外會執(zhí)行一些其他邏輯
userService.test();
上面是通過cglib來實現(xiàn)的代理對象的創(chuàng)建闯参,是基于父子類的,被代理類(UserService)是父類悲立,代理類是子類鹿寨,代理對象就是代理類的實例對象。
2薪夕、JDK的動態(tài)代理
UserService target = new UserService();
// UserInterface接口的代理對象
Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before...");
Object result = method.invoke(target, args);
System.out.println("after...");
return result;
}
});
UserInterface userService = (UserInterface) proxy;
userService.test();
jdk的動態(tài)代理必須依賴接口脚草,所以生產(chǎn)的代理對象和被代理對象是兄弟關系,再采用依賴注入時必須使用接口接收代理對象原献。
二馏慨、ProxyFactory
上面我們介紹了兩種動態(tài)代理技術埂淮,那么在Spring中進行了封裝,封裝出來的類叫做ProxyFactory写隶,表示是創(chuàng)建代理對象的一個工廠倔撞,使用起來會比上面的更加方便,比如:
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor(){
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();
通過ProxyFactory樟澜,我們可以不再關心到底是用cglib還是jdk動態(tài)代理了误窖,ProxyFactory會幫我們?nèi)ヅ袛啵绻鸘serService實現(xiàn)了接口秩贰,那么ProxyFactory底層就會用jdk動態(tài)代理霹俺,如果沒有實現(xiàn)接口,就會用cglib技術毒费,上面的代碼丙唧,就是由于UserService實現(xiàn)了UserInterface接口,所以最后產(chǎn)生的代理對象是UserInterface類型觅玻。
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);
}
}
同時我們也看一下Advice的接口定義
/**
* Tag interface for Advice. Implementations can be any type
* of advice, such as Interceptors.
*
* @author Rod Johnson
* @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $
*/
public interface Advice {
}
三想际、Advisor
跟Advice類似的還有一個Advisor的概念,一個Advisor是有一個Pointcut和一個Advice組成的溪厘,通過Pointcut可以指定要需要被代理的邏輯胡本,比如一個UserService類中有兩個方法,按上面的例子畸悬,這兩個方法都會被代理侧甫,被增強,那么我們現(xiàn)在可以通過Advisor蹋宦,來控制到具體代理哪一個方法披粟,比如:
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(new PointcutAdvisor() {
@Override
public Pointcut getPointcut() {
return new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.getName().equals("test");
}
};
}
@Override
public Advice getAdvice() {
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
};
}
@Override
public boolean isPerInstance() {
return false;
}
});
UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();
四、Spring中創(chuàng)建代理對象的方式
下面我們來看一下Spring中創(chuàng)建代理對象的方式冷冗,首先來看ProxyFactoryBean:
@Bean
public ProxyFactoryBean userServiceProxy(){
UserService userService = new UserService();
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(userService);
proxyFactoryBean.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
return proxyFactoryBean;
}
@Resource(name = "userServiceProxy")
private UserInterface userInterface;
@PostConstruct
public void print(){
userInterface.test();
}
ProxyFactoryBean實現(xiàn)了FactoryBean接口守屉。FactoryBean是Spring中一個比較重要的切入點,在bean的初始化過程中Spring會調(diào)用getObject()方法獲取到代理對象蒿辙,并放入bean容器拇泛,所以當我們通過@Resource(name = "userServiceProxy")注解拿到的其實是UserInterface的代理對象
/**
* Return a proxy. Invoked when clients obtain beans from this factory bean.
* Create an instance of the AOP proxy to be returned by this factory.
* The instance will be cached for a singleton, and create on each call to
* {@code getObject()} for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
@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();
}
}
ProxyFactoryBean得自己指定被代理的對象,那么我們可以通過BeanNameAutoProxyCreator來通過指定某個bean的名字思灌,來對該bean進行代理碰镜。
@Bean
public MethodInterceptor myAroundAdvise(){
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
};
}
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("userSe*");
beanNameAutoProxyCreator.setInterceptorNames("myAroundAdvise");
beanNameAutoProxyCreator.setProxyTargetClass(true);
return beanNameAutoProxyCreator;
}
BeanNameAutoProxyCreator中實現(xiàn)了getAdvicesAndAdvisorsForBean()方法
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;
}
}
}
}
}
return DO_NOT_PROXY;
}
該方法就會根據(jù)beanName找到對應的Interceptors,而BeanNameAutoProxyCreator本身繼承于AbstractAutoProxyCreator习瑰,AbstractAutoProxyCreator作為BeanPostProcessor就會在bean初始化后postProcessAfterInitialization()方法中創(chuàng)建該bean的代理對象放入bean容器绪颖。
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;
}
細節(jié)在wrapIfNecessary中,此時就會調(diào)用BeanNameAutoProxyCreator.getAdvicesAndAdvisorsForBean()方法
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;
}
// Create proxy if we have advice.
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;
}
通過BeanNameAutoProxyCreator可以對批量的Bean進行AOP,并且指定了代理邏輯柠横,指定了一個InterceptorName窃款,也就是一個Advise,前提條件是這個Advise也得是一個Bean牍氛,這樣Spring才能找到的晨继,但是BeanNameAutoProxyCreator的缺點很明顯,它只能根據(jù)beanName來指定想要代理的Bean搬俊。
而通過DefaultAdvisorAutoProxyCreator會直接去找所有Advisor類型的Bean紊扬,根據(jù)Advisor中的PointCut和Advice信息,確定要代理的Bean以及代理邏輯唉擂。
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor(){
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.addMethodName("test");
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(pointcut);
defaultPointcutAdvisor.setAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
return defaultPointcutAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
return defaultAdvisorAutoProxyCreator;
}
當使用DefaultAdvisorAutoProxyCreator時餐屎,AbstractAutoProxyCreator.wrapIfNecessary方法中,就會調(diào)用DefaultAdvisorAutoProxyCreator的父類AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean()方法
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();
}
進入findEligibleAdvisors方法玩祟,我們就可以看到此時會先找到所有的Advisor bean腹缩,然后再去和beanClass匹配,最后得到滿足條件的Advisor空扎,并排序:
/**
* Find all eligible Advisors for auto-proxying this class.
* @param beanClass the clazz to find advisors for
* @param beanName the name of the currently proxied bean
* @return the empty List, not {@code null},
* if there are no pointcuts or interceptors
* @see #findCandidateAdvisors
* @see #sortAdvisors
* @see #extendAdvisors
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
五藏鹊、Spring中創(chuàng)建代理對象的細節(jié)
當我們進入AbstractAutoProxyCreator.wrapIfNecessary()方法,最后就會看到createAopProxy().getProxy(classLoader)方法转锈,getProxy方法分別對應JDK和cglib兩種實現(xiàn)盘寡,首先來看JDK的實現(xiàn),Spring中JdkDynamicAopProxy類封裝了JDK的實現(xiàn)細節(jié)撮慨,并且實現(xiàn)了InvocationHandler接口
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable
在Proxy.newProxyInstance(classLoader, proxiedInterfaces, this)時將當前JdkDynamicAopProxy對象傳入竿痰,這樣實際執(zhí)行的就是JdkDynamicAopProxy.invoke方法,這里使用了典型的策略模式
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);
}
這里的關鍵邏輯就是拿到方法的攔截器鏈甫煞,List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);然后遞歸調(diào)用MethodInterceptor.invoke方法,invoke方法比較長冠绢,這里只截取關鍵的幾行:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
...
// 根據(jù)代理對象和方法找到攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
//如果chain為空抚吠,直接將target傳入,通過反射執(zhí)行被代理對象的方法
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
//構建MethodInvocation
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
...
}
進入invocation.proceed()
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//這里會判斷是否是動態(tài)方法匹配攔截器
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
//普通攔截器
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
通常我們定義的都是普通攔截器弟胀,進入((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this)會發(fā)現(xiàn)有很多的實現(xiàn)楷力,我們以AfterReturningAdviceInterceptor為例,注意這里傳入了this
public Object invoke(MethodInvocation mi) throws Throwable {
//這里其實仍然執(zhí)行的是ReflectiveMethodInvocation.proceed()
Object retVal = mi.proceed();
this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
return retVal;
}
到這里其實就十分清晰了孵户,正是通過遞歸的方式來執(zhí)行多個MethodInterceptor
六萧朝、AnnotationAwareAspectJAutoProxyCreator
在我們實際使用中,很少直接創(chuàng)建AdvisorBean夏哭,更多是通過@Aspect來使用的检柬,并且通過引入@EnableAspectJAutoProxy來獲得Spring對注解@Aspect的支持,這里其實就用到了AnnotationAwareAspectJAutoProxyCreator
//通過@Import引入AspectJAutoProxyRegistrar
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
進入AspectJAutoProxyRegistrar:
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//在此處注冊了AnnotationAwareAspectJAutoProxyCreator的BeanDefinition
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
AnnotationAwareAspectJAutoProxyCreator重寫了findCandidateAdvisors方法竖配,增加了對@Aspect解析:
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
七何址、SpringAop關鍵類的繼承關系
AnnotationAwareAspectJAutoProxyCreator繼承了AbstractAdvisorAutoProxyCreator里逆,重寫了findCandidateAdvisors()方法,AbstractAdvisorAutoProxyCreator只能找到所有Advisor類型的Bean對象用爪,但是AnnotationAwareAspectJAutoProxyCreator除開可以找到所有Advisor類型的Bean對象原押,還能把@Aspect注解所標注的Bean中的@Before等注解及方法進行解析,并生成對應的Advisor對象偎血。
八诸衔、最后我們來總結一下,SpringAop其實就是通過BeanPostProcessor結合JDK或者cglib的動態(tài)代理來實現(xiàn)對bean的增強颇玷,結合使用了工廠模式笨农、策略模式、責任鏈模式等亚隙,對使用者屏蔽掉了底層實現(xiàn)磁餐,可見設計者的深厚功力。所以說多刷源碼真的漲見識~~~