最近工做中我都是基於註解實現AOP功能,經常使用的開啓AOP的註解是@EnableAspectJAutoProxy,咱們就從它入手。
java
AnnotationAwareAspectJAutoProxyCreator查看其中文註釋(以下),肯定它就是AOP的核心類!--溫安適 20191020spring
/**
1.AspectJAwareAdvisorAutoProxyCreator的子類
,用於處理當前應用上下文中的註解切面
2.任何被AspectJ註解的類將自動被識別。
3.若SpringAOP代理模式能夠識別,優先使用Spring代理模式。
4.它覆蓋了方法執行鏈接點
5.若是使用<aop:include>元素,
則只有名稱與include模式匹配的@aspectj bean才被視爲切面
,並由spring自動代理。
6. Spring Advisors的處理請查閱,
org.springframework.aop
.framework.autoproxy.AbstractAdvisorAutoProxyCreator
*/
@SuppressWarnings("serial")
public class AnnotationAwareAspectJAutoProxyCreator
extends AspectJAwareAdvisorAutoProxyCreator {
//...省略實現
}註解切面
複製代碼
雖然找到了核心類,可是並無找到核心方法!下面咱們嘗試畫類圖肯定核心方法。緩存
AnnotationAwareAspectJAutoProxyCreator的部分類圖。
bash
//AbstractAutoProxyCreator中的postProcessAfterInitialization實現
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
複製代碼
發現發現疑似方法wrapIfNecessary,查看其源碼以下,發現createProxy方法。肯定找對了地方。ide
protected Object wrapIfNecessary
(Object bean, String beanName, Object cacheKey) {
if (beanName != null && 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;
}
// 建立代理
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;
}
複製代碼
即AnnotationAwareAspectJAutoProxyCreator實現BeanPostProcessor的postProcessAfterInitialization方法,在該方法中由wrapIfNecessary實現了AOP的功能。 wrapIfNecessary中有2個和核心方法post
查看源碼以下,默認實如今AbstractAdvisorAutoProxyCreator中。ui
@Override
@Nullable
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方法,就幹了3件事this
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;
}
複製代碼
AnnotationAwareAspectJAutoProxyCreator 重寫了findCandidateAdvisors,下面咱們看看具體實現了什麼spa
@Override
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) {
//@Aspect註解的類在這裏除了
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
複製代碼
從該方法咱們能夠看到處理@Aspect註解的bean的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。 這個方法以下:.net
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
//找到全部BeanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 必須注意,bean會提早暴露,並被Spring容器緩存,可是這時還不能織入。
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
//找到全部被@Aspect註解的類
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//解析封裝爲Advisor返回
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
複製代碼
這個方法能夠歸納爲:
衆所周知,建立代理的經常使用的2種方式是:JDK建立和CGLIB,下面咱們就看看這2中建立代理的例子。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyMain {
public static void main(String[] args) {
JDKProxyTestInterface target = new JDKProxyTestInterfaceImpl();
// 根據目標對象建立代理對象
JDKProxyTestInterface proxy =
(JDKProxyTestInterface) Proxy
.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new JDKProxyTestInvocationHandler(target));
// 調用代理對象方法
proxy.testProxy();
}
interface JDKProxyTestInterface {
void testProxy();
}
static class JDKProxyTestInterfaceImpl
implements JDKProxyTestInterface {
@Override
public void testProxy() {
System.out.println("testProxy");
}
}
static class JDKProxyTestInvocationHandler
implements InvocationHandler {
private Object target;
public JDKProxyTestInvocationHandler(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("執行前");
Object result= method.invoke(this.target,args);
System.out.println("執行後");
return result;
}
}
複製代碼
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyTest {
static class CglibProxyService {
public CglibProxyService(){
}
void sayHello(){
System.out.println(" hello !");
}
}
static class CglibProxyInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object sub, Method method,
Object[] objects, MethodProxy methodProxy)
throws Throwable {
System.out.println("before hello");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("after hello");
return object;
}
}
public static void main(String[] args) {
// 經過CGLIB動態代理獲取代理對象的過程
Enhancer enhancer = new Enhancer();
// 設置enhancer對象的父類
enhancer.setSuperclass(CglibProxyService.class);
// 設置enhancer的回調對象
enhancer.setCallback(new CglibProxyInterceptor());
// 建立代理對象
CglibProxyService proxy= (CglibProxyService)enhancer.create();
System.out.println(CglibProxyService.class);
System.out.println(proxy.getClass());
// 經過代理對象調用目標方法
proxy.sayHello();
}
}
複製代碼
類型 | jdk建立動態代理 | cglib建立動態代理 |
---|---|---|
原理 | java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理 | cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,經過修改其字節碼生成子類來處理 |
核心類 | Proxy 建立代理利用反射機制生成一個實現代理接口的匿名類InvocationHandler 方法攔截器接口,須要實現invoke方法 | net.sf.cglib.proxy.Enhancer:主要加強類,經過字節碼技術動態建立委託類的子類實例net.sf.cglib.proxy.MethodInterceptor:方法攔截器接口,須要實現intercept方法 |
侷限性 | 只能代理實現了接口的類 | 不能對final修飾的類進行代理,也不能處理final修飾的方法 |
Spring的選擇選擇如何代理時在DefaultAopProxyFactory 中。
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);
}
}
//...
}
複製代碼
//exposeProxy=true AopContext 能夠訪問,proxyTargetClass=true CGLIB生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)
總結下Spring如何選擇建立代理的方式:
Spring如何實現AOP?,您能夠這樣說: