通知是对目标对象方法的增强,而引入可以动态为目标对象实现新的接口,实现对类的增强。
引入的使用
目标类
public class DogService {
public void hi() {
System.out.println("wangwang");
}
}
增强接口
public interface CatService {
void eat();
}
增强接口实现类
public class CatServiceImpl implements CatService {
@Override
public void eat() {
System.out.println("cat eat");
}
}
切面类
package com.morris.spring.config;
import com.morris.spring.service.CatService;
import com.morris.spring.service.CatServiceImpl;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@Aspect
public class IntroduceConfig {
@DeclareParents(value = "com.morris.spring.service.*+", defaultImpl = CatServiceImpl.class)
private CatService catService;
}
测试类
package com.morris.spring.demo.annotation;
import com.morris.spring.config.IntroduceConfig;
import com.morris.spring.service.CatService;
import com.morris.spring.service.DogService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class IntroduceDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(DogService.class);
applicationContext.register(IntroduceConfig.class);
applicationContext.refresh();
DogService dogService = applicationContext.getBean(DogService.class);
dogService.hi();
CatService catService = (CatService) dogService;
catService.eat();
}
}
运行结果如下:
cat eat
wangwang
从运行结果可以发现DogService拥有了CatService接口的能力,可以使用arthas工具导出内存中动态代理生成的对象:
public class DogService$$EnhancerBySpringCGLIB$$15587e5c extends DogService implements CatService, SpringProxy, Advised, Factory {
源码实现
注解的扫描
解析带有@Aspect注解类下面的有@DeclareParents注解的属性:
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisors
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
... ...
// Find introduction fields.
// 引入
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
遍历所有带有@DeclareParents注解的属性,封装成为DeclareParentsAdvisor对象。
org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getDeclareParentsAdvisor
private Advisor getDeclareParentsAdvisor(Field introductionField) {
DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class);
if (declareParents == null) {
// Not an introduction field
return null;
}
if (DeclareParents.class == declareParents.defaultImpl()) {
throw new IllegalStateException("'defaultImpl' attribute must be set on DeclareParents");
}
return new DeclareParentsAdvisor(
introductionField.getType(), declareParents.value(), declareParents.defaultImpl());
}
目标类的匹配
调用IntroductionAdvisor.getClassFilter().matches()进行类的匹配,上面注入的DeclareParentsAdvisor对象是IntroductionAdvisor的子类,也就是会根据@DeclareParents注解中指定的表达式与类的权限定名进行匹配。
org.springframework.aop.support.AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class<?>, boolean)
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 DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> defaultImpl) {
this(interfaceType, typePattern,
new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
}
将目标类封装到了DelegatePerTargetObjectIntroductionInterceptor,而DelegatePerTargetObjectIntroductionInterceptor是一个MethodInterceptor,最终目标方法的执行都会调到MethodInterceptor.invoke():
public Object invoke(MethodInvocation mi) throws Throwable {
if (isMethodOnIntroducedInterface(mi)) {
Object delegate = getIntroductionDelegateFor(mi.getThis());
// Using the following method rather than direct reflection,
// we get correct handling of InvocationTargetException
// if the introduced method throws an exception.
// 调用目标方法
Object retVal = AopUtils.invokeJoinpointUsingReflection(delegate, mi.getMethod(), mi.getArguments());
// Massage return value if possible: if the delegate returned itself,
// we really want to return the proxy.
if (retVal == delegate && mi instanceof ProxyMethodInvocation) {
retVal = ((ProxyMethodInvocation) mi).getProxy();
}
return retVal;
}
return doProceed(mi);
}