springel表达式解析_spring源码系列:Aop基础编程以及
SpringAop基于。。。
AOP编程中的基本概念
1. 连接点: 程序执⾏某个特定位置,如类的初始化前后,某个⽅法调⽤前后,⽅法报出异常后,⼀个类或者⼀段代码拥有⼀些边界性质的
特定点。Spring仅⽀持⽅法的连接点
2. 切点: 每个程序都拥有多个连接点。AOP通过切点定位连接点,⼀个切点可以对应多个连接点。
3. 增强: 增强是⼀段代码。是织⼊到⽬标类的连接点上的⼀段代码。
4. ⽬标对象: 增强逻辑的织⼊⽬标类
5. 引介: 引介是特殊的增强,他为类添加⼀些属性和⽅法
6. 织⼊: 将增强添加到具体⽬标对象的连接点的过程
7. 切⾯: 切⾯是由切点和增强组成
Spring中的概念
advisor: 封装了SpringAop的切点和通知(类似为切⾯) 后⾯我们把advisor结尾的类称为切⾯类
advice: 通知,也就是增强。后⾯我们把spring中以advice结尾的类称为增强类
creator: 相当于织⼊(只不过spring是通过动态代理织⼊增强的) 为了⽅便称呼我们后⾯把creator结尾的类成为织⼊类
核⼼类
advisorCreator⾃动织⼊类:
BeanNameAutoProxyCreator: 根据指定的名称创建代理对象,通过设置advisor,可以对指定的beanName进⾏代理。⽀持模糊
AbstractAdvisorAutoProxyCreator: 扫描所有的advisor的实现类。动态匹配每⼀个类,判断是否可以被代理。默认的实现类是DefaultAdvisorAutoProxyCreator
AspectJAwareAdvisorAutoProxyCreator: AspectJ的实现⽅式,spring最常⽤的实现⽅式。其⼦类
(AnnotationAwareAspectJAutoProxyCreator)是默认的⽀持⽅式,会扫描@Aspect注解的类,⽣产对应的切⾯。
advisor核⼼类(都集成Advisor接⼝)
StaticMethodMatcherPointcut: 静态⽅法切⾯,抽象类。定义了⼀个classFilter,通过重写getClassFilter()⽅法来指定切⾯规则。
另外实现了StaticMethodMatcher接⼝,通过重写matches来指定⽅法匹配规则
StaticMethodMatcherPointcutAdvisor: 静态⽅法匹配切⾯,扩展了排序⽅法。
NameMatchMethodPointcut: 名称匹配切⾯,通过指定⽅法集合变量mappedNames,模糊匹配。
NameMatchMethodPointcutAdvisor: ⽅法名称切⾯,内部封装了NameMatchMethodPointcut,通过设置⽅法名称模糊匹配规则和通知来实现切⾯功能
DefaultPointcutAdvisor: 默认的切⾯类
RegexpMethodPointcutAdvisor: ⽤于⽀持正则表达式的切⾯类,可⽀持函多个正则表达式
NameMatchMethodPointcutAdvisor: ⽅法名称切⾯
InstantiationModelAwarePointcutAdvisorImpl: ⾃动封装的切⾯实现。在⾃动织⼊的时候会默认会把AspectJ注解默认包装改该类。⽐较常⽤的切⾯类
advice增强核⼼类
AspectJMethodBeforeAdvice: 前置增强(@Before标注的⽅法会被解析成该通知)
AspectJAfterReturningAdvice: 后置增强(@AfterReturning 标注的⽅法会被解析成该通知)
AspectJAroundAdvice: 环绕增强(@Around标注的⽅法会被解析成该通知)
AspectJAfterAdvice: 返回增强(@After 标注的⽅法会被解析成该通知)忽略异常
SpringAop基于AspectJ注解⽅式
⽬标对象
@Component
public class TargetA {
public void sayHello(){
System.out.println("sayHello");
}
}
增强
@Component
@Aspect
public class ProxyA {
@Pointcut("execution(* org.springframework.apo..*.*(..))")
public void point(){
}
@Before("point()")
public void before(){
System.out.println("begin say..");
}
@After("point()")
public void after(){
System.out.println("after say ...");
}
}
启动类
@ComponentScan("org.springframework.apo")
spring ioc注解@EnableAspectJAutoProxy
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(App.class);
TargetA bean = Bean(TargetA.class);
bean.sayHello();
}
}
可以看到在spring中我们只需要定义增强 其他的不需要我们关⼼。 spring的creator会帮我织⼊到⽬标类。上⾯的流程最关键的两点 其⼀是AspectJ连接点表达式⽐较关键 其⼆是在启动类上加@EnableAspectAutoProxy注解(springboot引⼊了spring-boot-starter-aop就不需要再⼿动Enabled)。下⾯我们从注解⼊⼿看⼀下 spring织⼊的整个流程。
Spring AOP源码分析
启动注解EnableAspectJAutoProxy
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
我们看到上述代码中使⽤@Import标签向spring容器中导⼊了⼀个AspectJAutoProxyRegistrar。继续跟进AspectJAutoProxyRegistrar
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//向IOC容器中注⼊AnnotationAwareAspectJAutoProxyCreator
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (Boolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (Boolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
上⾯代码其实主要是向容器中加了AnnotationAwareAspectJAutoProxyCreator 这个织⼊类。并根据我们的配置(注解中有两个属性 后续会讲解)。到这这个注解的使命就完成了。那为什么像springIOC容器注⼊了⼀个AnnotationAwareAspectJAutoProxyCreator 就能实现织⼊的能⼒呢?下⾯我们从这个类⼊⼿了解⼀下spring的整个织⼊流程。
类的继承关系
在看spring源码的时候我们可以发现 spring框架中⼤量运⽤了模板⽅法模式。所以只要出现Abstract开头的类 我们就应该好好的去看⼀下。分析这⼀部分的源码我们就从第第⼀个抽象类⼊⼿AbstractAutoProxyCreator。
看⼀下初始化过程
⽗类初始化AbstractAutoProxyCreator
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
}
}
⼦类初始化
public class AnnotationAwareAspectJAutoProxyCreator extends AspectJAwareAdvisorAutoProxyCreator {
//这个⽅法是在bean初始化之前调⽤在spring启动期间会把BeanFactory注⼊进来是⼀个初始化⽅法。
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
//ReflectiveAspectJAdvisorFactory是⼀个⽀持AspectJ注解的类。可以解析AspectJ注解包装成Advisor。简单的理解是对AspectJ的语法的⽀持。
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
//这⾥是对ReflectiveAspectJAdvisorFactory的包装内部真正解析AspectJ注解的是ReflectiveAspectJAdvisorFactory类。
this.aspectJAdvisorsBuilder =
new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
}
可以发现它实现了SmartInstantiationAwareBeanPostProcessor 。这个接⼝是springIOC容器的扩展接⼝其最顶层的⽗接⼝是BeanPostProcessor。在springIOC容器启动和 bean的创建 初始化前后调⽤。如果对这⼀块⽐较模糊可以去看⼀下BeanFactoryPostProcessor和BeanPostProcessor这两个⽗接⼝衍⽣出来的⼏个接⼝的注释。⾥⾯对于调⽤点的注释还挺清楚。我们这⾥就不做过多解释了。
下⾯我们把这个类中我们需要⽤的⽅法复制出来
//这个⽅法是InstantiationAwareBeanPostProcessor接⼝中的⽅法是在bean实例化之前被调⽤
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !ains(beanName)) {
//advisedBeans⽤于存储不能被代理的bean 如果当前bean出现在集合中⽴马返回
if (ainsKey(cacheKey)) {
return null;
}
//如果当前类继承 Advice,Pointcut,Advisor,AopInfrastructureBean等这些类也不能被
//代理
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
/
/得到⽬标源这是⼀次尝试因为如果我们设置customTargetSourceCreators 这个属性这个时候就
//会获取我们设置的TargetSource对象如果没设置就跳过了这个⽅法。下⾯的代理过程我们暂且先不管
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if (targetSource != null) {
if (StringUtils.hasLength(beanName)) {
//如果到确实设置了TargetSource 就加⼊到缓存集合
this.targetSourcedBeans.add(beanName);
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, Class());
return proxy;
}
return null;
}
下⾯我们看⼀下shouldSkip这个⽅法 ⼦类的实现
@Override
protected boolean shouldSkip(Class<?> beanClass, String beanName) {
// 从bean⼯⼚中查所有的advisor 如果当前bean的名字在当前advisor的列表中则跳过不需要代理
//暂时不展开
List<Advisor> candidateAdvisors = findCandidateAdvisors();
for (Advisor advisor : candidateAdvisors) {
if (advisor instanceof AspectJPointcutAdvisor &&
((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
return true;
}
}
return super.shouldSkip(beanClass, beanName);
}
上⾯我们分析了postProcessBeforeInstantiation⽅法 如果设置⾃定义的TargetSourceCreator 就只做了⼀件事件 到所有的增强并封装成切⾯
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论