Spring AOP——源码分析
【阅读前提】:需了解 AOP 注解开发流程:链接
一、注解 @EnableAspectJAutoProxy
在配置类中添加注解@EnableAspectJAutoProxy,便开启了 AOP(面向切面编程) 功能。此注解也是了解 AOP 源码的入口。
@EnableAspectJAutoProxy
@Configuration
public class MainConfigOfAOP {
【1】@EnableAspectJAutoProxy 是什么?我们进入注解,查看其源码如下:发现调用 EnableAspectJAutoProxy 类,同时使用 @Import 注解向容器中导入 AspectJAutoProxyRegistrar 组件:作用是给容器中注册自定义的 Bean。
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
【2】进入 AspectJAutoProxyRegistrar 类,调用 registerBeanDefinitions 中的 register...Necessary 方法注册组件。
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { //向容器(registry)中注入组件
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
【3】 进入 register...Necessary 方法,通过源码分析:该方法向容器中注册一个 AnnotationAwareAspectJAutoProxyCreator (支持注解模式的面向切面自动代理创建器)组件,其名称为 internalAutoProxyCreator 。需要注意的是其注册的是一个 BeanDefinition(Bean 的定义信息,并没有实例化。后续分析时会说到) 。
1 //debug 进来后,发现cls参数的值等于 AnnotationAwareAspectJAutoProxyCreator 这个参数也是直接写死的,如下:。
2 //registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
3 @Nullable
4 private static BeanDefinition registerOrEscalateApcAsRequired(
5 Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
6
7 Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
8 //AUTO_PROXY_CREATOR_BEAN_NAME == internalAutoProxyCreator
9 //因第一次进来,所以容器中不存在 internalAutoProxyCreator
10 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
11 BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
12 if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
13 int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
14 int requiredPriority = findPriorityForClass(cls);
15 if (currentPriority < requiredPriority) {
16 apcDefinition.setBeanClassName(cls.getName());
17 }
18 }
19 return null;
20 }
21 //创建一个新的对象封装 cls
22 RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
23 beanDefinition.setSource(source);
24 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
25 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
26 //将封装的cls对象注册到容器中,并将名称定义为AUTO_PROXY_CREATOR_BEAN_NAME == internalAutoProxyCreator 就上上述判断的语句。
27 //此时我们就应该分析 AnnotationAwareAspectJAutoProxyCreator对象的作用
28 registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
29 return beanDefinition;
30 }
二、研究 AnnotationAwareAspectJAutoProxyCreator
此自动代理创建器的内部功能,其等价于 AOP 的主要功能。 此类的继承结构如下:
我们进入自动代理的抽象父类 AbstractAutoProxyCreator 中发现,其实现了 SmartInstantiationAwareBeanPostProcessor 后置处理器(在 bean 初始化前后做一些操作,AOP 的特点)和 BeanFactoryAware 自动装配 BeanFactory。
@SuppressWarnings("serial")
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
AOP原理分析技巧:【看给容器中注册了什么组件, 这个组件什么时候工作,这个组件的功能是什么?】,研究透这些,原理也就清楚了。
我们从 AbstractAutoProxyCreator 父类向 AnnotationAwareAspectJAutoProxyCreator 子类的顺序,查看其内部关于后置处理器和自动装备的方法并加入断点:
【1】AbstractAutoProxyCreator :包含后置处理器前后的两个方法和自动装配的方法。
1 //后置处理器相关的方法1
2 @Override
3 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
4 Object cacheKey = getCacheKey(beanClass, beanName);
5
6 if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
7 if (this.advisedBeans.containsKey(cacheKey)) {
8 return null;
9 }
10 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
11 this.advisedBeans.put(cacheKey, Boolean.FALSE);
12 return null;
13 }
14 }
15
16 //后置处理器相关的方法2
17 @Override
18 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
19 if (bean != null) {
20 Object cacheKey = getCacheKey(bean.getClass(), beanName);
21 if (this.earlyProxyReferences.remove(cacheKey) != bean) {
22 return wrapIfNecessary(bean, beanName, cacheKey);
23 }
24 }
25 return bean;
26 }
27
28 //自动装备相关的方法
29 @Override
30 public void setBeanFactory(BeanFactory beanFactory) {
31 this.beanFactory = beanFactory;
32 }
【2】AbstractAdvisorAutoProxyCreator:重写了 setBeanFactory 方法。
1 //自动装备方法
2 @Override
3 public void setBeanFactory(BeanFactory beanFactory) {
4 super.setBeanFactory(beanFactory);
5 if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
6 throw new IllegalArgumentException(
7 "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
8 }
9 initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
10 }
【3】对 2中的 initBeanFactory 方法进行了重写。
1 @Override
2 protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
3 super.initBeanFactory(beanFactory);
4 if (this.aspectJAdvisorFactory == null) {
5 this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
6 }
7 this.aspectJAdvisorsBuilder =
8 new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
9 }
三、Debug 测试类流程梳理
【1】创建 IOC 容器,传入主配置类 MainConfigOfAOP
//获取容器中的类
ApplicationContext ApplicationContext =
new AnnotationConfigApplicationContext(MainConfigOfAOP.class);
【2】调用 AnnotationConfigApplicationContext 构造器:注册配置类和刷新容器(创建容器中的所有Bean,类似于初始化容器)
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//创建对象
this();
//注册配置类
register(annotatedClasses);
//刷新容器
refresh();
}
【3】调用 refresh 方法:主要查看 registerBeanPostProcessors(beanFactory); 方法,其作用是注册 bean 后置处理器,用方便来拦截 bean 的创建。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
....
// 注册 bean 后置处理器,用来拦截 bean 的创建
registerBeanPostProcessors(beanFactory);
....
}
【4】进入 registerBeanPostProcessors 调用的方法:先获取 IOC 容器中已经定义了的需要创建对象的所有后置处理器BeanPostProcessor(已定义:指我们在解析配置类的时候@EnableAspectJAutoProxy 会为我们注册一个 AnnotationAwareAspectJAutoProxyCreator 后置处理器的定义,包括默认的一些后置处理器的定义)例如:
上述列表中的 internalAutoProxyCreator 后置处理器,就是我们分析 @EnableAspectJAutoProxy 时注入的那个处理器。后置处理的注册分为以下三种情况:
■ 优先注册实现了 PriorityOrdered(优先级)接口的 BeanPostProcessors;
■ 其次注册实现了Ordered 接口的 BeanPostProcessors;
■ 注册所有常规 Beanpstprocessors;
internalAutoProxyCreator 后置处理器实现了 Ordered 接口。分析代码可知:【根据 bean定义名称 internalAutoProxyCreator 从 beanFactory 中获取注入的后置处理器】调用的方法 = beanFactory.getBean(ppName, BeanPostProcessor.class);
1 public static void registerBeanPostProcessors(
2 ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
3 //获取ioc容器中已经定义了的需要创建对象的所有 BeanPostProcessor
4 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
5
6 //也会注意一些其他后置处理器,bean 是在 beanPostProcessor 实例化期间创建的,即 bean 不适合由所有 beanPostProcessors 处理。这个其实不重要,可以省略...
7 int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
8 beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
9 //判断哪些后置处理器配置了优先级
10 for (String ppName : postProcessorNames) {
11 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
12 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
13 priorityOrderedPostProcessors.add(pp);
14 if (pp instanceof MergedBeanDefinitionPostProcessor) {
15 internalPostProcessors.add(pp);
16 }
17 }else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
18 orderedPostProcessorNames.add(ppName);
19 }else {
20 nonOrderedPostProcessorNames.add(ppName);
21 }
22 }
23 // 优先注册实现了 PriorityOrdered(优先级) 的 BeanPostProcessors
24 sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
25 registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
26
27 // 其次注册实现了Ordered 接口的 BeanPostProcessors.
28 List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
29 for (String ppName : orderedPostProcessorNames) {
30 //根据 bean定义的名称internalAutoProxyCreator 从 beanFactory 中获取注入的后置处理器
31 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
32 orderedPostProcessors.add(pp);
33 if (pp instanceof MergedBeanDefinitionPostProcessor) {
34 internalPostProcessors.add(pp);
35 }
36 }
37 sortPostProcessors(orderedPostProcessors, beanFactory);
38 registerBeanPostProcessors(beanFactory, orderedPostProcessors);
39
40 // 注册所有常规beanpstprocessors。
41 List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
42 for (String ppName : nonOrderedPostProcessorNames) {
43 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
44 nonOrderedPostProcessors.add(pp);
45 if (pp instanceof MergedBeanDefinitionPostProcessor) {
46 internalPostProcessors.add(pp);
47 }
48 }
49 registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
50
51 // 最后,重新注册所有内部beanpstprocessors。
52 sortPostProcessors(internalPostProcessors, beanFactory);
53 registerBeanPostProcessors(beanFactory, internalPostProcessors);
【5】进入上述所说的 beanFactory.getBean(ppName, BeanPostProcessor.class); 方法如下:因第一次进入容器,因此获取不到实例。会通过 getSingleton 方法创建 BeanPostProcessor 的实例,并保存到容器中。
1 @Override
2 public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
3 return doGetBean(name, requiredType, null, false);
4 }
5
6
7 //上述方法内部调用的是 doGetBean(name, requiredType, null, false); 代码如下:
8 @SuppressWarnings("unchecked")
9 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
10 @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
11 //因为第一次获取,容器中不存在此实例。因此 sharedInstance==null
12 Object sharedInstance = getSingleton(beanName);
13 if (sharedInstance != null && args == null) {
14 ...
15 }else {
16 // 创建 bean 实例
17 if (mbd.isSingleton()) {
18 sharedInstance = getSingleton(beanName, () -> {
19 try {
20 return createBean(beanName, mbd, args);
21 }catch (BeansException ex) {
22 destroySingleton(beanName);
23 throw ex;
24 }
25 });
26 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
27 }
28 }
【6】创建 internalAutoProxyCreator 的 AnnotationAwareAspectJAutoProxyCreator 实例。步骤如下:
//1、创建bean的实例
createBean(beanName, mbd, args);
//2、给Bean 的各属性赋值
populateBean(beanName, mbd, instanceWrapper);
//3、初始化 bean ,比较重要,因为后置处理器就是在此前后进行工作的
exposedObject = initializeBean(beanName, exposedObject, mbd);
【7】重点是:初始化 initializeBean 方法,查看实现的步骤如下:
1 //1、调用 invokeAwareMethods 处理Aware 接口的方法回调,beanName=internalAutoProxyCreator 实现了 BeanAware 接口
2 invokeAwareMethods(beanName, bean);
3 //2、应用后置处理器 BeforeInitialization
4 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
5 //3、执行自定义的初始化方法
6 invokeInitMethods(beanName, wrappedBean, mbd);
7 //4、执行后置处理器的 After方法
8 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
9
10 //下面是上述方法的具体实现
11
12 //1、invokeAwareMethods 实现如下:
13 private void invokeAwareMethods(final String beanName, final Object bean) {
14 if (bean instanceof Aware) {
15 //.....
16 //实现了 BeanFactoryAware 接口,因此执行 setBeanFactory.
17 //bean==AnnotationAwareAspectJAutoProxyCreator
18 if (bean instanceof BeanFactoryAware) {
19 ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
20 }
21 }
22 }
23
24
25 //2、applyBeanPostProcessorsBeforeInitialization 实现如下:
26 @Override
27 public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
28 throws BeansException {
29
30 Object result = existingBean;
31 //获取所有的后置处理器,执行前置Before 处理器。
32 for (BeanPostProcessor processor : getBeanPostProcessors()) {
33 Object current = processor.postProcessBeforeInitialization(result, beanName);
34 if (current == null) {
35 return result;
36 }
37 result = current;
38 }
39 return result;
40 }
41
42 //3、invokeInitMethods 方法的具体实现
43 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
44 throws Throwable {
45
46 boolean isInitializingBean = (bean instanceof InitializingBean);
47 if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
48 if (logger.isTraceEnabled()) {
49 logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
50 }
51 if (System.getSecurityManager() != null) {
52 try {
53 AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
54 ((InitializingBean) bean).afterPropertiesSet();
55 return null;
56 }, getAccessControlContext());
57 }
58 catch (PrivilegedActionException pae) {
59 throw pae.getException();
60 }
61 }
62 else {
63 ((InitializingBean) bean).afterPropertiesSet();
64 }
65 }
66
67 if (mbd != null && bean.getClass() != NullBean.class) {
68 String initMethodName = mbd.getInitMethodName();
69 if (StringUtils.hasLength(initMethodName) &&
70 !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
71 !mbd.isExternallyManagedInitMethod(initMethodName)) {
72 invokeCustomInitMethod(beanName, bean, mbd);
73 }
74 }
75 }
76
77 //4、applyBeanPostProcessorsAfterInitialization 具体实现
78 @Override
79 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
80 throws BeansException {
81
82 Object result = existingBean;
83 for (BeanPostProcessor processor : getBeanPostProcessors()) {
84 Object current = processor.postProcessAfterInitialization(result, beanName);
85 if (current == null) {
86 return result;
87 }
88 result = current;
89 }
90 return result;
91 }
【8】执行 Aware 初始化时,会调用 setBeanFactory 方法,我们追下去会发现调用的是 AbstractAdvisorAutoProxyCreator 的setBeanFactory 方法(就是我们分析 AnnotationAwareAspectJAutoProxyCreator 继承关系时的父类 )。
1 @Override
2 public void setBeanFactory(BeanFactory beanFactory) {
3 //调用父类的 setBeanFactory
4 super.setBeanFactory(beanFactory);
5 if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
6 throw new IllegalArgumentException(
7 "AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
8 }
9 //AnnotationAwareAspectJAutoProxyCreator 方法对此进行了重写
10 initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
11 }
【9】进入 initBeanFactory 方法,我们知道此方法已被 AnnotationAwareAspectJAutoProxyCreator 重写:
1 //位于 AnnotationAwareAspectJAutoProxyCreator 类中
2 @Override
3 protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
4 super.initBeanFactory(beanFactory);
5 if (this.aspectJAdvisorFactory == null) {
6 //创建了放射的通知工厂
7 this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
8 }
9 this.aspectJAdvisorsBuilder =
10 new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
11 }
【10】最终 BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功,将其添加到 beanFactory 中。
1 for (String ppName : orderedPostProcessorNames) {
2 //实例 pp==AnnotationAwareAspectJAutoProxyCreator
3 BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
4 //放入 ordered后置处理器集合
5 orderedPostProcessors.add(pp);
6 if (pp instanceof MergedBeanDefinitionPostProcessor) {
7 internalPostProcessors.add(pp);
8 }
9 }
10 //将处理器按优先级排序
11 sortPostProcessors(orderedPostProcessors, beanFactory);
12 //调用注册方法
13 registerBeanPostProcessors(beanFactory, orderedPostProcessors);
14
15 //上述注册方法的内部代码
16 private static void registerBeanPostProcessors(
17 ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
18 //将后置处理器都添加到bean工厂
19 for (BeanPostProcessor postProcessor : postProcessors) {
20 beanFactory.addBeanPostProcessor(postProcessor);
21 }
22 }
四、后置处理器创建后的操作
【1】以上是创建和注册 AnnotationAwareAspectJAutoProxyCreator 的过程。接下来就是对创建后的流程进行说明:AnnotationAwareAspectJAutoProxyCreator 是继承 InstantiationAwareBeanPostProcessor 的后置处理器:我们在上面说的 IOC 容器初始化时,会调用 refresh 方法:我们进入此方法看下,我们之前分析 registerBeanPostProcessors 方法,接下来分析 finishBeanFactoryInitialization 方法(实例所有剩余的单实例bean)完成 BeanFactory 初始化工作。
1 @Override
2 public void refresh() throws BeansException, IllegalStateException {
3 synchronized (this.startupShutdownMonitor) {
4 //......
5 // 注册 bean后置处理器 来拦截 bean 的创建。
6 registerBeanPostProcessors(beanFactory);
7 //......
8 // 初始化特定上下文子类中的其他特殊bean。
9 onRefresh();
10 //......
11 // 实例化所有剩余的(非延迟初始化)单例。
12 finishBeanFactoryInitialization(beanFactory);
13 }
【2】遍历获取容器中所有的 Bean ,依次创建对象 getBean(beanName); 流程:getBean -> doGetBean() -> getSingleton(),getBean 方法如下:先从缓存中获取当前 bean,如果能获取到说明 bean 是之前被创建过的,直接使用,否则创建bean;只要是创建好的 bean 都会被缓存起来。
1 // 先检查单例缓存中是否有已存在手动注册的单例,如果存在说明之前bean已创建
2 Object sharedInstance = getSingleton(beanName);
3 //缓存中不存在 bean 时才创建该单例 bean
4 if (sharedInstance != null && args == null) {
5 //...
6 }else{
7 //创建bean实例。
8 if (mbd.isSingleton()) {
9 sharedInstance = getSingleton(beanName, () -> {
10 try {
11 return createBean(beanName, mbd, args);
12 }
13 catch (BeansException ex) {
14 destroySingleton(beanName);
15 throw ex;
16 }
17 });
18 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
19 }
20 }
【2.1】进入创建 bean 的步骤: createBean 方法,首先会调用 resolveBeforeInstantiation 方法,让 beanPostProcessors后置处理器有机会返回代理对象而不是目标 bean 实例。如果能返回则直接使用,如果不能则调用 doCreateBean 方法来创建实例。
1 @Override
2 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
3 throws BeanCreationException {
4 /*现获取类的基本信息 例如:
5 Root bean: class [org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator];
6 scope=singleton等等*/
7 RootBeanDefinition mbdToUse = mbd;
8 //......
9 //让beanPostProcessors有机会返回代理而不是目标bean实例。
10 Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
11 if (bean != null) {
12 return bean;
13 }
14 //通过此方法,先调用 aware、前置处理器、bean初始化、后置处理器 ,之前有分析过。
15 Object beanInstance = doCreateBean(beanName, mbdToUse, args);
16 }
【BeanPostProcessor 是在 Bean 对象创建完成初始化前后调用的】
【InstantiationAwareBeanPostProcessor 是在创建 bean 实例之前先尝试用后置处理器返回代理对象】
后置处理器与后置处理器不同,具体什么时候调用,需要根据不同情况而定。
【2.1.1】分析 resolveBeforeInstantiation 方法(让 beanPostProcessors 有机会返回代理对象):我们分析的 AnnotationAwareAspectJAutoProxyCreator 就是 InstantiationAwareBeanPostProcessor 类型的后置处理器。会在任何 bean 创建之前先尝试返回 bean 的代理实例。
1 @Nullable
2 protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
3 bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
4 if (bean != null) {
5 bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
6 }
7 }
8
9 //上面两个方法的源码展示
10 @Nullable
11 protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
12 //获取所有的后置处理器
13 for (BeanPostProcessor bp : getBeanPostProcessors()) {
14 //如果后置处理器是 InstantiationAwareBeanPostProcessor 类型的处理器则执行 postProcessBeforeInstantiation 方法。
15 //我们分析的 AnnotationAwareAspectJAutoProxyCreator 就是 InstantiationAwareBeanPostProcessor 类型的处理器
16 if (bp instanceof InstantiationAwareBeanPostProcessor) {
17 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
18 //***** 后续分析
19 Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
20 if (result != null) {
21 return result;
22 }
23 }
24 }
25 return null;
26 }
【2.1.1.1】接着分析上述的 postProcessBeforeInstantiation 方法:内容较多,放在五中分析。
【2.1.2】分析 doCreateBean 方法,之前有介绍过,我们在看下源码:就是对创建的目标类前后对后置处理器的方法进行初始化。才是真正创建一个 bean 的实例。
1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
2 throws BeanCreationException {
3 //创建 bean 实例
4 instanceWrapper = createBeanInstance(beanName, mbd, args);
5 //bean 属性赋值
6 populateBean(beanName, mbd, instanceWrapper);
7 //初始化 bean
8 exposedObject = initializeBean(beanName, exposedObject, mbd);
9 }
10
11
12 //初始化方法 initializeBean 的源码
13 protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
14 //初始化 aware 接口的类
15 invokeAwareMethods(beanName, bean);
16 //后置处理器 Before 方法初始化
17 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
18 //初始化类
19 invokeInitMethods(beanName, wrappedBean, mbd);
20 //后置处理器 after 方法初始化
21 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
22 //返回创建好的类
23 return wrappedBean;
24 }
五、postProcessBeforeInstantiation 方法分析
【1】每个 bean 创建之前,调用此方法。我们主要观察业务逻辑 MathCalculator 类和切面 LogAspects 类的创建。
1 //当bean = MathCalculator or LogAspects 我们着重分析此方法,其他的略过
2 @Override
3 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
4 Object cacheKey = getCacheKey(beanClass, beanName);
5
6 if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
7 //判断当前 bean 是否在 advisedBeans 中(保存了所有需要增加的 bean:意思就是添加了切面的内容),第一次进行肯定是不包含的所以会跳过
8 if (this.advisedBeans.containsKey(cacheKey)) {
9 return null;
10 }
11 //isInfrastructureClass 判断当前类是否为基础类型的,也就是实现了 Advice、Pointcut、Advisor、AopInfrastructureBean
12 //或者是否为切面注解标注的类 (@Aspect),第一个 MathCalculator = false
13 //shouldSkip 是否需要跳过:内部是获取候选的增强器(也就是切面内的通知方法)
14 //将所有的增强器封装成了 List<Advisor> 集合,增强器的类型是 InstantiationModelAwarePointcutAdvisor
15 if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
16 this.advisedBeans.put(cacheKey, Boolean.FALSE);
17 return null;
18 }
19 }
20 // targetSource = null
21 TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
22 if (targetSource != null) {
23 if (StringUtils.hasLength(beanName)) {
24 this.targetSourcedBeans.add(beanName);
25 }
26 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
27 Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
28 this.proxyTypes.put(cacheKey, proxy.getClass());
29 return proxy;
30 }
31 //直接返回空,进入我们配置类中,创建 MathCalculator 对象
32 return null;
33 }
【2】上述代码中的 shouldSkip 源码:
1 @Override
2 protected boolean shouldSkip(Class<?> beanClass, String beanName) {
3 //获取所有的增强器 考虑通过缓存方面名称列表进行优化
4 List<Advisor> candidateAdvisors = findCandidateAdvisors();
5 for (Advisor advisor : candidateAdvisors) {
6 //我们的增强器都是 InstantiationModelAwarePointcutAdvisor 类型的,不是AspectJPointcutAdvisor 所以跳过
7 if (advisor instanceof AspectJPointcutAdvisor &&
8 ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) {
9 return true;
10 }
11 }
12 //父类直接返回 false
13 return super.shouldSkip(beanClass, beanName);
14 }
【3】创建完 MathCalculator 后,调用 postProcessAfterInitialization
1 @Override
2 public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
3 if (bean != null) {
4 // cacheKey = calculator
5 Object cacheKey = getCacheKey(bean.getClass(), beanName);
6 //判断之前是否代理过
7 if (this.earlyProxyReferences.remove(cacheKey) != bean) {
8 //包装目标类,如果需要的话
9 return wrapIfNecessary(bean, beanName, cacheKey);
10 }
11 }
12 return bean;
13 }
【3.1】查看包装方法 wrapIfNecessary 的源码:分析后得出如下结论:以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候,代理对象就会执行通知方法的流程
1 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
2 //...... 省略的都是判断是否为切面类或以代理类
3 //如果需要就创建代理类
4 //getAdvicesAndAdvisorsForBean 获取能在当前类使用的增强器
5 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
6 if (specificInterceptors != DO_NOT_PROXY) {
7 //保存当前 bean 在advisedBeans 表示当前bean 被处理了
8 this.advisedBeans.put(cacheKey, Boolean.TRUE);
9 //创建代理对象 ****重点,返回的是一个通过 Cglib 代理的对象
10 Object proxy = createProxy(
11 bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
12 this.proxyTypes.put(cacheKey, proxy.getClass());
13 return proxy;
14 }
15
16 this.advisedBeans.put(cacheKey, Boolean.FALSE);
17 return bean;
【3.1.1】进入当前类使用的增强器方法:getAdvicesAndAdvisorsForBean
1 @Override
2 @Nullable
3 protected Object[] getAdvicesAndAdvisorsForBean(
4 Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
5 //获取可用的增强器
6 List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
7 if (advisors.isEmpty()) {
8 return DO_NOT_PROXY;
9 }
10 return advisors.toArray();
11 }
【3.1.1.1】进入获取可用增强器的方法:findEligibleAdvisors
1 protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
2 //获取后置增强器
3 List<Advisor> candidateAdvisors = findCandidateAdvisors();
4 //找到能在当前bean中使用的增强器(找那些方法能够切入到当前方法的)
5 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
6 extendAdvisors(eligibleAdvisors);
7 if (!eligibleAdvisors.isEmpty()) {
8 //对增强器进行了排序
9 eligibleAdvisors = sortAdvisors(eligibleAdvisors);
10 }
11 return eligibleAdvisors;
12 }
13
14 //上面获取当前bean中使用的增强器的方法源码
15 protected List<Advisor> findAdvisorsThatCanApply(
16 List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
17
18 ProxyCreationContext.setCurrentProxiedBeanName(beanName);
19 try {
20 //通过 AopUtils工具类获取所有的通知方法
21 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
22 }
23 finally {
24 ProxyCreationContext.setCurrentProxiedBeanName(null);
25 }
26 }
27
28 //工具类方法源码展示
29 public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
30 if (candidateAdvisors.isEmpty()) {
31 return candidateAdvisors;
32 }
33 List<Advisor> eligibleAdvisors = new ArrayList<>();
34 for (Advisor candidate : candidateAdvisors) {
35 //我们的增强器不是此类型
36 if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
37 eligibleAdvisors.add(candidate);
38 }
39 }
40 boolean hasIntroductions = !eligibleAdvisors.isEmpty();
41 for (Advisor candidate : candidateAdvisors) {
42 if (candidate instanceof IntroductionAdvisor) {
43 // already processed
44 continue;
45 }
46 //判断增强器是否可用,我们的都是可用的
47 if (canApply(candidate, clazz, hasIntroductions)) {
48 //将所有可以使用的增强器,加入到可用的增强器集合中
49 eligibleAdvisors.add(candidate);
50 }
51 }
52 return eligibleAdvisors;
53 }
54
55 //判断是否为可用的增强器的方法 canApply源码:
56 public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
57 if (advisor instanceof IntroductionAdvisor) {
58 return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
59 }
60 //查看切面的方法是否都能匹配
61 else if (advisor instanceof PointcutAdvisor) {
62 PointcutAdvisor pca = (PointcutAdvisor) advisor;
63 return canApply(pca.getPointcut(), targetClass, hasIntroductions);
64 }
65 else {
66 // It doesn't have a pointcut so we assume it applies.
67 return true;
68 }
69 }
【3.1.2】进入代理对象的创建方法:createProxy
1 protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
2 @Nullable Object[] specificInterceptors, TargetSource targetSource) {
3
4 if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
5 AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
6 }
7 //创建代理工厂
8 ProxyFactory proxyFactory = new ProxyFactory();
9 proxyFactory.copyFrom(this);
10
11 if (!proxyFactory.isProxyTargetClass()) {
12 if (shouldProxyTargetClass(beanClass, beanName)) {
13 proxyFactory.setProxyTargetClass(true);
14 }
15 else {
16 evaluateProxyInterfaces(beanClass, proxyFactory);
17 }
18 }
19 //获取所有的增强器,并保存在代理工厂
20 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
21 proxyFactory.addAdvisors(advisors);
22 proxyFactory.setTargetSource(targetSource);
23 customizeProxyFactory(proxyFactory);
24
25 proxyFactory.setFrozen(this.freezeProxy);
26 if (advisorsPreFiltered()) {
27 proxyFactory.setPreFiltered(true);
28 }
29 //使用代理工厂创建对象
30 return proxyFactory.getProxy(getProxyClassLoader());
31 }
【3.1.2.1】进入代理工厂创建对象的方法 proxyFactory.getProxy 的源码:
1 public Object getProxy(@Nullable ClassLoader classLoader) {
2 return createAopProxy().getProxy(classLoader);
3 }
4
5 //进入 createAopProxy().getProxy 内部的内部方法
6 @Override
7 public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
8 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
9 Class<?> targetClass = config.getTargetClass();
10 if (targetClass == null) {
11 throw new AopConfigException("TargetSource cannot determine target class: " +
12 "Either an interface or a target is required for proxy creation.");
13 }
14 //创建 JDK 代理或者 Cglib 代理。如果实现了接口则使用 JDK 代理,否则Cglib 代理
15 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
16 return new JdkDynamicAopProxy(config);
17 }
18 return new ObjenesisCglibAopProxy(config);
19 }
20 else {
21 return new JdkDynamicAopProxy(config);
22 }
23 }
六、目标方法执行
【1】容器中保存了组件的代理对象(cglib 增强后的对象),这个对象里面保存了详细信息(比如:增强器,目标对象......)
【2】CglibAopProxy.intercept(); 拦截目标方法执行如下:主要是根据 ProxyFactory 对象获取将要执行的目标方法的拦截器链。
1)、如果没有拦截器链,直接执行目标方法。
2)、如果有拦截器链,吧需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 方法。
1 @Override
2 @Nullable
3 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
4 Object oldProxy = null;
5 boolean setProxyContext = false;
6 Object target = null;
7 TargetSource targetSource = this.advised.getTargetSource();
8 try {
9 if (this.advised.exposeProxy) {
10 oldProxy = AopContext.setCurrentProxy(proxy);
11 setProxyContext = true;
12 }
13 target = targetSource.getTarget();
14 Class<?> targetClass = (target != null ? target.getClass() : null);
15 //根据 ProxyFactory 对象获取将要执行的目标方法的拦截器链
16 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
17 Object retVal;
18 //如果没有拦截器链,直接执行目标方法。
19 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
20 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
21 retVal = methodProxy.invoke(target, argsToUse);
22 }
23 //如果有拦截器链,吧需要执行的目标对象,目标方法,拦截器链等信息传入创建一个 CglibMethodInvocation 对象,并调用如下方法。
24 else {
25 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
26 }
27 retVal = processReturnType(proxy, target, method, retVal);
28 return retVal;
29 }
30 finally {
31 //......
32 }
33 }
【3】 拦截器链:List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice 的源码展示:
1)、List<Object> interceptorList 中保存了所有拦截器,总计5个。一个默认的 ExposeInvocationInterceptor 和 4个增强器。
2)、遍历所有的增强器,将其转为 Interceptor(拦截器):registry.getInterceptors(advisor);
1 @Override
2 public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
3 Advised config, Method method, @Nullable Class<?> targetClass) {
4
5 //......
6 //获取所有的增强器进行遍历
7 for (Advisor advisor : advisors) {
8 //判断是否为切面的增强器
9 if (advisor instanceof PointcutAdvisor) {
10 //......
11 //将增强器转化为 MethodInterceptor
12 MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
13 if (mm.isRuntime()) {
14 for (MethodInterceptor interceptor : interceptors) {
15 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
16 }
17 }
18 else {
19 interceptorList.addAll(Arrays.asList(interceptors));
20 }
21 }
22 else if (advisor instanceof IntroductionAdvisor) {
23 IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
24 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
25 Interceptor[] interceptors = registry.getInterceptors(advisor);
26 interceptorList.addAll(Arrays.asList(interceptors));
27 }
28 }
29 else {
30 Interceptor[] interceptors = registry.getInterceptors(advisor);
31 interceptorList.addAll(Arrays.asList(interceptors));
32 }
33 }
34
35 return interceptorList;
36 }
3)、将增强器转为 MethodInterceptor,转化方式如下:最终返回拦截器链(每一个通知方法又被包装为方法拦截器,后期都是利用 MethodInterceptor 机制)。
1 @Override
2 public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
3 List<MethodInterceptor> interceptors = new ArrayList<>(3);
4 Advice advice = advisor.getAdvice();
5 //如果是 MethodInterceptor 直接加入到 list 中
6 if (advice instanceof MethodInterceptor) {
7 interceptors.add((MethodInterceptor) advice);
8 }
9 //如果不是则,使用 AdvisorAdapter 将增强器转为 MethodInterceptor
10 for (AdvisorAdapter adapter : this.adapters) {
11 if (adapter.supportsAdvice(advice)) {
12 interceptors.add(adapter.getInterceptor(advisor));
13 }
14 }
15 if (interceptors.isEmpty()) {
16 throw new UnknownAdviceTypeException(advisor.getAdvice());
17 }
18 return interceptors.toArray(new MethodInterceptor[0]);
19 }
【4】、拦截器链有了之后,创建 CglibMethodInvocation 并执行 proceed 方法:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
七、拦截器链的触发过程
【1】拦截器链展示:除了默认的方法 ExposeInvocationInterceptor 剩下的 4个都是我们切面中的方法。
【2】如果没有拦截器执行目标方法执行代理对象 CglibMethodInvocation 的 proceed 方法:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
【3】进入 proceed 方法:
1 @Override
2 @Nullable
3 public Object proceed() throws Throwable {
4 //判断连接器栏的长度是否 == 0,此方法会在拦截器链的最后一个链时调用
5 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
6 //执行目标方式,输入为:MathCalculator...div...
7 return invokeJoinpoint();
8 }
9 //获取下标=0的拦截器 ExposeInvocationInterceptor
10 Object interceptorOrInterceptionAdvice =
11 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
12 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
13 //下标0 跳过......
14 }
15 else {
16 // this=ReflectiveMethodInvocation
17 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
18 }
19 }
【4】进入 (MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 方法:会循环调用 list 中的拦截器,直到后置处理器:AspectJMethodBeforeAdvice
1 //ThreadLocal 线程共享数据 (共享 MethodInvocation)
2 private static final ThreadLocal<MethodInvocation> invocation =
3 new NamedThreadLocal<>("Current AOP method invocation");
4
5 @Override
6 public Object invoke(MethodInvocation mi) throws Throwable {
7 //获取 invocation
8 MethodInvocation oldInvocation = invocation.get();
9 //将当前方法,放入 invocation
10 invocation.set(mi);
11 try {
12 //执行 cglib 的proceed() 就获取到了下标为1的拦截器 AspectJAfterThrowingAdvice
13 return mi.proceed();
14 }
15 finally {
16 //执行后置通知
17 invocation.set(oldInvocation);
18 }
19 }
【5】 当advice = AspectJMethodBeforeAdvice 后置处理器时,invoke 方法如下:
1 @Override
2 public Object invoke(MethodInvocation mi) throws Throwable {
3 //执行后置处理器的 before 方法
4 //输出如下:div运行。。。@Before:参数列表是:{[2, 3]}
5 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
6 //进入上述展示的 processd 方法,此时进入第一个判断语句,执行目标方法
7 return mi.proceed();
8 }
【7】 后置处理器的 After 方法执行的 invoke 方法展示:最终执行结果的返回方法。
1 @Override
2 public Object invoke(MethodInvocation mi) throws Throwable {
3 try {
4 return mi.proceed();
5 }
6 finally {
7 //执行 after 方法:div结束。。。@After
8 invokeAdviceMethod(getJoinPointMatch(), null, null);
9 }
10 }
【8】上述分析的流程图如下:根据链表循环向下执行,当最后一个后置处理器的 before 执行完成后,进行目标方法,并进行回流执行拦截器的目标方法。
Spring AOP——源码分析的更多相关文章
- spring AOP源码分析(三)
在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- Spring AOP 源码分析 - 筛选合适的通知器
1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...
- Spring AOP 源码分析系列文章导读
1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...
- Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理
AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...
- 5.2 Spring5源码--Spring AOP源码分析二
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
- 5.2 spring5源码--spring AOP源码分析二--切面的配置方式
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
- spring aop 源码分析(三) @Scope注解创建代理对象
一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...
- 最简 Spring AOP 源码分析!
前言 最近在研究 Spring 源码,Spring 最核心的功能就是 IOC 容器和 AOP.本文定位是以最简的方式,分析 Spring AOP 源码. 基本概念 上面的思维导图能够概括了 Sprin ...
随机推荐
- 初探AOP
1.背景介绍 1.什么是AOP 1)在OOP(面向对象编程)中,正是这种分散在各处且与对象核心功能无关的代码(横切代码)的存在,使得模块复用难度增加. 2)AOP则将封装好的对象剖开,找出其中对多个 ...
- python机器学习——朴素贝叶斯算法
背景与原理: 朴素贝叶斯算法是机器学习领域最经典的算法之一,仍然是用来解决分类问题的. 那么对于分类问题,我们的模型始终是:用$m$组数据,每条数据形如$(x_{1},...,x_{n},y)$,表示 ...
- Apple Sources
1. libsystem_malloc.dylib的源码 https://opensource.apple.com/tarballs/libmalloc/ .这里有多个版本(例如用otool找到iOS ...
- 元素定位xpath路径中添加参数的方法
在某次自动化测试中,需要定位下拉列表(非select列表)中不同的元素,我想到了利用参入参数的方式来实现,经过多次尝试,得到如下方法,与大家分享 例如在通过text定位某个元素时,self.find_ ...
- php后端遇到的问题
1.用文件记录日志,会有并发问题
- redis字段使用说明
Set(集合)增删改查: #删除当前选择数据库中的所有key127.0.0.1:6379> flushdbOK#生成set集合,添加4个数据127.0.0.1:6379> sadd set ...
- 开始 go
为什么开始想转 go ? 毕业三年多,一直从事的是 Java , 大学学的也是 Java ,本来想一直干下去的,可是似乎 Java 水涨船高,面试要求也越来越高. 曾经一起毕业的同事自学 go ,已经 ...
- Delphi书籍大全【阿里云盘】
「marco cantu的Object Pascal Handbook」等文件 https://www.aliyundrive.com/s/sJtUo8ziUpV 提取码: 5tp6点击链接保存,或者 ...
- Markdown基础学习
Markdown学习 一级标题 #加空格 标题二 二级标题 ##加空格 如此类推 标题三 或者Ctrl+123456 字体 加粗 两个** hello world 倾斜一个* hello world ...
- javascript原型,继承
//普通对象 //函数对象(有原型 prototy 的属性) //原型的应用 继承 function Amial(){ this.type = '小于' } function cat(name){ t ...