1 Обзор
1.1 Пример
Самое основное использование, после создания бизнес-интерфейса и класса реализации, настроить<aop:config>....</aop:config>
метка для указания<aop:pointcut
а также<aop:advisor
. Пример выглядит следующим образом:
1.1.1 Создание интерфейса и класса реализации
интерфейс:
public interface MockService {
public String hello(String s);
}
Класс реализации:
public class MockServiceImpl implements MockService {
@Override
public String hello(String s) {
System.out.println("execute hello");
return s;
}
}
1.1.2 Реализовать перехват метода
реализовать интерфейсorg.aopalliance.intercept.MethodInterceptor
public class CustomInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("CustomInterceptor before");
Object result = invocation.proceed();
System.out.println("CustomInterceptor after");
return result;
}
}
1.1.3 XML-файл конфигурации
Создайтеaop.xml
, размещенный в каталоге ресурсов:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"
default-lazy-init="false" default-autowire="byName">
<!-- 实现来org.aopalliance.intercept.MethodInterceptor的拦截器 -->
<bean id="customInterceptor" class="com.xxx.yyy.CustomInterceptor"/>
<bean id="mockService" class="com.xxx.yyy.MockServiceImpl"/>
<aop:config proxy-target-class="true">
<aop:pointcut id="interceptorPointCuts" expression="execution(* com.xxx.yyy..*.*(..))"/>
<aop:advisor advice-ref="customInterceptor" pointcut-ref="interceptorPointCuts"/>
</aop:config>
</beans>
1.1.4 Бег
public class Main {
public static void main(String[] args){
ApplicationContext context = new ClassPathXmlApplicationContext("aop.xml");
MockService mockService = (MockService) context.getBean("mockService");
mockService.hello("mock");
}
}
вернуть:
CustomInterceptor before
execute hello
CustomInterceptor after
1.2 Процесс реализации АОП
Во время запуска среды Spring он будет называтьсяAbstractApplicationContext.refresh()
, процесс реализации АОП, то есть отсюда.
- 1 дюйм
obtainFreshBeanFactory()
Во время выполнения загрузитьaop.xml, и согласноnamespaceоказатьсяaop
соответствующийNamespaceHandler:AopNamespaceHandler
; - 2
AopNamespaceHandler
в, найтиconfigсоответствует этикеткеBeanDefinitionParserобъект реализации, т.ConfigBeanDefinitionParser
; - 3 Выполнить
ConfigBeanDefinitionParser.parse
, выполняет две функции:- к
AspectJAwareAdvisorAutoProxyCreator
Зарегистрировать BeanDefinition; - Разобрать
pointcut
,advisor
И другие метки, и связанные с ними объекты, зарегистрированные как BeanDefinition.
- к
- 4 Зарегистрируйте BeanPostProcessor:
AspectJAwareAdvisorAutoProxyCreator
это класс реализации BeanPostProcessorAbstractAutoProxyCreator
подкласс . После регистрации BeanPostProcessor,AspectJAwareAdvisorAutoProxyCreator
Будет вызываться во время прокси-процесса создания bean-компонента Spring. - 5 Создать прокси и дополнить его советником, есть несколько основных шагов:
- создать прокси;
- Найти подходящего советника;
- Расширенный прокси.
2 AopNamespaceHandler
Чтобы загрузить среду Spring, вам нужно вызвать AbstractApplicationContext.refresh().
В методе refresh() выполнитеConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
При создании BeanFacotry загрузите и проанализируйте ресурс xml.
Во время этого процесса он вызоветBeanDefinitionParserDelegate.parseCustomElement
Выполните синтаксический анализ тега расширения:
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
// 获取namespace
String namespaceUri = getNamespaceURI(ele);
// 根据文件META-INF/spring.handlers,获取对应的NamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 调用NamespaceHandler.parse方法,返回BeanDefinition
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
Подробный процесс см.Анализ исходного кода и реализация пользовательской конфигурации тегов Spring.
для<aop:config/>
, весна будетxmlns
идтиMETA-INF/spring.handlers
Найдите в файле соответствующий класс разрешения пространства имен:http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
.
существуетAopNamespaceHandler
середина:registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
так:
aop
Класс разрешения пространства именAopNamespaceHandler
-
<aop:config/>
Класс синтаксического анализа для тегаConfigBeanDefinitionParser
,существуетConfigBeanDefinitionParser
середина,<aop:config/>
Отдельные элементы определения анализируются какBeanDefinition
.
3 ConfigBeanDefinitionParser
ConfigBeanDefinitionParser
ДостигнутоBeanDefinitionParser
интерфейс, вparse(Element element, ParserContext parserContext)
В методе реализованы две части функций:
- 1 Зарегистрируйте BeanDefinition в среде Spring:
AspectJAwareAdvisorAutoProxyCreator
; - 2 Разберите pointcut, советник и т. д. конфигурации xml в серию BeanDefinitions.
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
// 注册AspectJAwareAdvisorAutoProxyCreator为BeanDefinition
configureAutoProxyCreator(parserContext, element);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt: childElts) {
String localName = parserContext.getDelegate().getLocalName(elt);
if (POINTCUT.equals(localName)) {
// 解析pointcut
parsePointcut(elt, parserContext);
}
else if (ADVISOR.equals(localName)) {
// 解析advisor
parseAdvisor(elt, parserContext);
}
else if (ASPECT.equals(localName)) {
parseAspect(elt, parserContext);
}
}
parserContext.popAndRegisterContainingComponent();
return null;
}
в:
private static final String POINTCUT = "pointcut";
private static final String ADVISOR = "advisor";
private static final String ASPECT = "aspect";
3.1 AspectJAwareAdvisorAutoProxyCreator
3.1.1 Функция
-
AspectJAwareAdvisorAutoProxyCreator
даAbstractAutoProxyCreator
подкласс; - AbstractAutoProxyCreator реализует интерфейс
BeanPostProcessor
; - AbstractAutoProxyCreator в
postProcessAfterInitialization
реализация, призывwrapIfNecessary
Делайте bean-проксирование.
@Override
public Object postProcessAfterInitialization(@Nullable 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;
}
В процессе создания экземпляра компонента Spring вызоветBeanPostProcessor
Для обработки до и после генерации bean-компонента aop использует это:
передачаAbstractAutoProxyCreator.postProcessAfterInitialization
метод, согласноpointcut
найти соответствующийadvisor
, прокси боб.
3.1.2 Регистрация BeanDefinition
Поток выполнения кода:
-
1 ConfigBeanDefinitionParser.configureAutoProxyCreator;
-
2 AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element);
public static void registerAspectJAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { // 注册BeanDefinition BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary( parserContext.getRegistry(), parserContext.extractSource(sourceElement)); // 设置class-proxy useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext); }
-
3 AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary;
-
4 AopConfigUtils.registerOrEscalateApcAsRequired:
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
//// 省略代码
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
наконец сгенерированный
AspectJAwareAdvisorAutoProxyCreator
BeanDefinition, beanNameorg.springframework.aop.config.internalAutoProxyCreator
.в то же время,
useClassProxyingIfNecessary
метод, согласно **aop:config/**серединаproxy-target-class
, который устанавливает родительский класс AspectJAwareAdvisorAutoProxyCreatorProxyConfig
изproxyTargetClass
Атрибуты.
3.2 Парсинг pointcut
Разобрать<aop:pointcut id="interceptorPointCuts" expression="execution(* com.xxx.yyy..*.*(..))"/>
,регистрAbstractExpressionPointcut
BeanDefinition.
3.2.1 parsePointcut
private AbstractBeanDefinition parsePointcut(Element pointcutElement, ParserContext parserContext) {
String id = pointcutElement.getAttribute(ID);
// 获取表达式 配置中的 expression="execution(* com.xxx.yyy..*.*(..))"
String expression = pointcutElement.getAttribute(EXPRESSION);
AbstractBeanDefinition pointcutDefinition = null;
try {
this.parseState.push(new PointcutEntry(id));
// 使用AspectJExpressionPointcut,为pointcut创建BeanDefinition,
pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(pointcutElement));
String pointcutBeanName = id;
if (StringUtils.hasText(pointcutBeanName)) {
// 以id为beanName注册AspectJExpressionPointcut为bean.
parserContext.getRegistry().registerBeanDefinition(pointcutBeanName, pointcutDefinition);
}
else {
// 自动生成beanName注册AspectJExpressionPointcut为bean.
pointcutBeanName = parserContext.getReaderContext().registerWithGeneratedName(pointcutDefinition);
}
parserContext.registerComponent(
new PointcutComponentDefinition(pointcutBeanName, pointcutDefinition, expression));
}
finally {
this.parseState.pop();
}
return pointcutDefinition;
}
3.2.2 createPointcutDefinition
- 1
aop:pointcut
решаетAspectJExpressionPointcut
объект. - 2
AspectJExpressionPointcut extends AbstractExpressionPointcut
- 3
expression
даAbstractExpressionPointcut
свойства
protected AbstractBeanDefinition createPointcutDefinition(String expression) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(AspectJExpressionPointcut.class);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
beanDefinition.setSynthetic(true);
beanDefinition.getPropertyValues().add(EXPRESSION, expression);
return beanDefinition;
}
3.3 Анализ советников
Разобрать<aop:advisor advice-ref="customInterceptor" pointcut-ref="interceptorPointCuts"/>
,регистрDefaultBeanFactoryPointcutAdvisor
BeanDefinition.
3.3.1 parseAdvisor
- 1 звонок
createAdvisorBeanDefinition
создать советник; - 2 звонка
parsePointcutProperty
Получить точечный разрез.
private void parseAdvisor(Element advisorElement, ParserContext parserContext) {
// 1 创建bean : DefaultBeanFactoryPointcutAdvisor
AbstractBeanDefinition advisorDef = createAdvisorBeanDefinition(advisorElement, parserContext);
String id = advisorElement.getAttribute(ID);
try {
this.parseState.push(new AdvisorEntry(id));
String advisorBeanName = id;
// 2 注册bean : DefaultBeanFactoryPointcutAdvisor
if (StringUtils.hasText(advisorBeanName)) {
parserContext.getRegistry().registerBeanDefinition(advisorBeanName, advisorDef);
}
else {
advisorBeanName = parserContext.getReaderContext().registerWithGeneratedName(advisorDef);
}
// 3 解析 pointcut-ref="interceptorPointCuts"
Object pointcut = parsePointcutProperty(advisorElement, parserContext);
if (pointcut instanceof BeanDefinition) {
// 返回的是有`pointcut`构造的BeanDefinition(AspectJExpressionPointcut对象),则设置`DefaultBeanFactoryPointcutAdvisor.pointcut = pointcut`
advisorDef.getPropertyValues().add(POINTCUT, pointcut);
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef, (BeanDefinition) pointcut));
}
else if (pointcut instanceof String) {
// 返回的是beanName,则设置`DefaultBeanFactoryPointcutAdvisor.pointcut`为一个运行时Bean引用。
advisorDef.getPropertyValues().add(POINTCUT, new RuntimeBeanReference((String) pointcut));
parserContext.registerComponent(
new AdvisorComponentDefinition(advisorBeanName, advisorDef));
}
}
finally {
this.parseState.pop();
}
}
3.3.2 createAdvisorBeanDefinition
- 1 Создать
DefaultBeanFactoryPointcutAdvisor
BeanDefinition, DefaultBeanFactoryPointcutAdvisor — этоPointcutAdvisor
реализация ; - 2 Анализ
advice-ref
Получите beanName bean-компонента советника, то есть customInterceptor в aop.xml. - 3
DefaultBeanFactoryPointcutAdvisor extends AbstractBeanFactoryPointcutAdvisor
,использоватьadvice-ref
настраиватьadviceBeanName
атрибут, то есть предыдущийcustomInterceptor
.
private static final String ADVICE_BEAN_NAME = "adviceBeanName";
private AbstractBeanDefinition createAdvisorBeanDefinition(Element advisorElement, ParserContext parserContext) {
// 创建`DefaultBeanFactoryPointcutAdvisor`的BeanDefinition;
RootBeanDefinition advisorDefinition = new RootBeanDefinition(DefaultBeanFactoryPointcutAdvisor.class);
advisorDefinition.setSource(parserContext.extractSource(advisorElement));
// 解析`advice-ref`获取advice的Bean的beanName;
String adviceRef = advisorElement.getAttribute(ADVICE_REF);
if (!StringUtils.hasText(adviceRef)) {
parserContext.getReaderContext().error(
"'advice-ref' attribute contains empty value.", advisorElement, this.parseState.snapshot());
}
else {
// 设置AbstractBeanFactoryPointcutAdvisor的adviceBeanName属性
advisorDefinition.getPropertyValues().add(
ADVICE_BEAN_NAME, new RuntimeBeanNameReference(adviceRef));
}
if (advisorElement.hasAttribute(ORDER_PROPERTY)) {
advisorDefinition.getPropertyValues().add(
ORDER_PROPERTY, advisorElement.getAttribute(ORDER_PROPERTY));
}
return advisorDefinition;
}
3.3.3 parsePointcutProperty
- 1 атрибут имеет
pointcut
, затем используйте выражение для вызова createPointcutDefinition и возвращайтесь сразу после создания bean-компонента AspectJExpressionPointcut. - 2 иначе вернуться
pointcut-ref
Определяет компонент как Pointcut.
так:pointcut имеет приоритет над pointcut-ref, и pointcut-ref больше не анализируется, если есть pointcut.
private Object parsePointcutProperty(Element element, ParserContext parserContext) {
if (element.hasAttribute(POINTCUT) && element.hasAttribute(POINTCUT_REF)) {
parserContext.getReaderContext().error(
"Cannot define both 'pointcut' and 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
else if (element.hasAttribute(POINTCUT)) {
// 属性有`pointcut`,则使用expression调用createPointcutDefinition,构造AspectJExpressionPointcut的bean后直接返回。
String expression = element.getAttribute(POINTCUT);
AbstractBeanDefinition pointcutDefinition = createPointcutDefinition(expression);
pointcutDefinition.setSource(parserContext.extractSource(element));
// 返回BeanDefinition
return pointcutDefinition;
}
else if (element.hasAttribute(POINTCUT_REF)) {
String pointcutRef = element.getAttribute(POINTCUT_REF);
if (!StringUtils.hasText(pointcutRef)) {
parserContext.getReaderContext().error(
"'pointcut-ref' attribute contains empty value.", element, this.parseState.snapshot());
return null;
}
// 返回pointcut-ref的beanName
return pointcutRef;
}
else {
parserContext.getReaderContext().error(
"Must define one of 'pointcut' or 'pointcut-ref' on <advisor> tag.",
element, this.parseState.snapshot());
return null;
}
}
3.4 BeanDefinition, зарегистрированный во время синтаксического анализа
- BeanPostProcessor :
AspectJAwareAdvisorAutoProxyCreator
, beanNameorg.springframework.aop.config.internalAutoProxyCreator
; - точечный разрез:
AbstractExpressionPointcut
, установлен атрибут выражения; - советник:
DefaultBeanFactoryPointcutAdvisor
, для атрибута Pointcut установлено значениеAbstractExpressionPointcut
.
4 Зарегистрируйте BeanPostProcessor
В методе AbstractApplicationContext.refresh() создайтеConfigurableListableBeanFactory
, выполнитregisterBeanPostProcessors
Зарегистрируйтесь в среде SpringBeanPostProcessor
.
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
AspectJAwareAdvisorAutoProxyCreator
На этом этапе добавляется в список BeanPostProcessors, используемых для обработки создания bean-компонентов.
Краткий процесс выглядит следующим образом:
- 1 звонок
PostProcessorRegistrationDelegate.registerBeanPostProcessors
; - 2 проход
beanFactory.getBean(ppName, BeanPostProcessor.class);
Получить список BeanPostProcessors; - 3 Выполнить
beanFactory.addBeanPostProcessor(postProcessor)
.
5 Создавайте bean-компоненты и улучшайте
5.1 createProxy
Весна создает бобы вAbstractAutowireCapableBeanFactory.doCreateBean
В методе:
- существует
AbstractAutowireCapableBeanFactory.doCreateBean
называется вinitializeBean
:
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
- существует
initializeBean
середина:
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
-
applyBeanPostProcessorsAfterInitialization
Выполнен метод BeanPostProcessor.postProcessAfterInitialization:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
-
AbstractAutoProxyCreator.postProcessAfterInitialization
Просто выполните его здесь:
@Override
public Object postProcessAfterInitialization(@Nullable 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 в:
// Create proxy if we have advice.
// 1 查找advisor
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 2 创建proxy,并使用advisor进行增强
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
5.2 Найдите подходящих советников
AbstractAutoProxyCreator.getAdvicesAndAdvisorsForBean
это абстрактный метод, используемый подклассамиAbstractAdvisorAutoProxyCreator
выполнить.
AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean
называетсяfindEligibleAdvisors
, Для достижения двух основных процессов:
- 1 Получить кандидатов в советники;
- 2 Отфильтруйте подходящие советники.
/*
beanClass:要代理的类
beanName:当前要代理的bean的beanName
*/
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 1 获取候选的advisors
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 2 过滤出匹配的advisors
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
5.2.1 findCandidateAdvisors
передачаBeanFactoryAdvisorRetrievalHelper.findAdvisorBeans
, чтобы получить все bean-компоненты, реализующие интерфейс Advisor.Основные фрагменты кода следующие:
-
1 Найдите beanName, который реализует интерфейс Advisor:
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false);
-
2 Получить bean-компоненты по beanName:
List<Advisor> advisors = new LinkedList<>(); .... advisors.add(this.beanFactory.getBean(name, Advisor.class)); .... return advisors;
5.2.2 findAdvisorsThatCanApply
Отфильтровать соответствующий советник, в основном через AopUtils.findAdvisorsThatCanApply, вызовcanApply
выполнить:
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
if (candidateAdvisors.isEmpty()) {
return candidateAdvisors;
}
List<Advisor> eligibleAdvisors = new LinkedList<>();
for (Advisor candidate : candidateAdvisors) {
// 调用 canApply
if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
eligibleAdvisors.add(candidate);
}
}
boolean hasIntroductions = !eligibleAdvisors.isEmpty();
for (Advisor candidate : candidateAdvisors) {
if (candidate instanceof IntroductionAdvisor) {
// already processed
continue;
}
// 调用canApply
if (canApply(candidate, clazz, hasIntroductions)) {
eligibleAdvisors.add(candidate);
}
}
return eligibleAdvisors;
}
5.2.3 canApply
- 1 Если интерфейс
IntroductionAdvisor
, затем вызовите IntroductionAdvisor.ClassFilter.matchs для оценки; - 2 Если интерфейс
PointcutAdvisor
(Например, DefaultBeanFactoryPointcutAdvisor, созданный ранее), сначала вызовите PointcutAdvisor.ClassFilter.matches для оценки, а затем MethodMatcher.getMethodMatcher() для оценки.
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
if (advisor instanceof IntroductionAdvisor) {
return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
}
else if (advisor instanceof PointcutAdvisor) {
PointcutAdvisor pca = (PointcutAdvisor) advisor;
return canApply(pca.getPointcut(), targetClass, hasIntroductions);
}
else {
// It doesn't have a pointcut so we assume it applies.
return true;
}
}
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
Assert.notNull(pc, "Pointcut must not be null");
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
MethodMatcher methodMatcher = pc.getMethodMatcher();
if (methodMatcher == MethodMatcher.TRUE) {
// No need to iterate the methods if we're matching any method anyway...
return true;
}
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
classes.add(targetClass);
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
for (Method method : methods) {
if ((introductionAwareMethodMatcher != null &&
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
5.3 Использование советника для улучшения агента
существуетAbstractAutoProxyCreator.createProxy
Реализовано в:
- 1 Создать ПроксиФабрику
- 2 Определить проксицелевой класс
- 3 buildAdvisors
- 4 Выполнить getProxy
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创建ProxyFactory
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// 判断proxyTargetClass
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// buildAdvisors
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 执行getProxy
return proxyFactory.getProxy(getProxyClassLoader());
}
5.3.1 DefaultAopProxyFactory.createAopProxy
proxyFactory.getProxy
, требуетсяAopProxy
достигать,AopProxy
Создание, вDefaultAopProxyFactory
, возвращаетJdkDynamicAopProxy
илиCglibAopProxy
.
@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);
}
}
5.3.2 JdkDynamicAopProxy
JdkDynamicAopProxy реализуетjava.lang.reflect.InvocationHandler
интерфейс, вinvoke(Object proxy, Method method, Object[] args)
Реализовать прокси. Фрагмент кода выглядит следующим образом:
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
передача
ReflectiveMethodInvocation.proceed()
Прокси реализован.
5.3.3 ObjenesisCglibAopProxy
ObjenesisCglibAopProxy — этоCglibAopProxy
Подкласс, логика прокси реализована вCglibAopProxy
внутри.
Когда массив обратного вызова получен в CglibAopProxy, создается объект DynamicAdvisedInterceptor.
private Callback[] getCallbacks(Class<?> rootClass){
//省略代码
// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
//省略代码
}
DynamicAdvisedInterceptor
Достигнутоorg.springframework.cglib.proxy.MethodInterceptor
интерфейс, вintercept
Способ оформления в агентстве:
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
CglibMethodInvocation — это
ReflectiveMethodInvocation
Подкласс , поэтому также вызываетReflectiveMethodInvocation.proceed()
Прокси реализован.