一、注册组件

@ComponentScan

扫描指定包下的组件。

String[] value():扫描基础包范围
Filter[] includeFilters():扫描并获取符合过滤规则的组件
Filter[] excludeFilters():扫描并排除符合过滤规则的组件- 过滤规则由@Filter定义

@Filter

定义扫描包的组件过滤规则。

FilterType type():过滤类型- ANNOTATION:按照是否标记注解- ASSIGNABLE_TYPE:按照类型,包括子类/实现类- CUSTOM:自定义过滤规则
Class<?>[] classes():type对应的类

举例:扫描当前注解所在包下所有的类,只扫描出类上标注@Controller注解的类进行获取。

@ComponentScan(includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})

自定义组件过滤规则:

@Configuration
@ComponentScan(includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyTypeFilter.class)})
public class MainConfig {}public class MyTypeFilter implements TypeFilter {/*** 过滤规则:获取到类名中包含 s 字符的类* @param metadataReader:读取到当前正在扫描类的信息* @param metadataReaderFactory:可以获取到其他任何类的信息*/@Overridepublic boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {// 获取到当前扫描类的信息ClassMetadata classMetadata = metadataReader.getClassMetadata();// 如果扫描类包含字符 s 就返回true if (classMetadata.getClassName().contains("s")) {return true;}return false;}
}

@Scope

容器对象的作用范围,默认对象是单实例bean。

String value():指定作用范围的类型- prototype:多实例的,IOC容器启动并不会去调用方法创建对象在容器中,每次获取的时候才会调用方法创建对象。- singleton:单实例的,IOC容器启动会调用方法创建对象放到容器中。以后获取直接从容器中拿(map.get())。- request:同一次请求创建一个实例。- session:同一个session创建一个实例。

举例:创建一个Person对象,需要每次获取都是不同的实例对象。

@Bean
@Scope("prototype")
public Person person() {return Person();
}

@Lazy

懒加载,对于单实例bean在容器启动时不创建对象,而是在第一次使用(获取)bean时创建并初始化对象。

@Bean
@Lazy
public Person person() {return Person();
}

@Conditional

定义创建bean对象的条件。

Class<? extends Condition>[] value():指定实现Condition接口的类用于匹配创建条件

举例:如果在Linux操作系统下,创建Person bean对象。

/*** 使用@Conditional来定义,如果在Linux下就创建这个bean* @Conditional:定义创建bean对象的条件*/
@Bean("linus")
@Conditional(value = LinuxCondition.class)
public Person person() {return new Person();
}// 实现Condition来定义匹配条件
public class LinuxCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 通过上下文来获取程序运行环境Environment environment = context.getEnvironment();// 获取操作系统String property = environment.getProperty("os.name");if (property.contains("linux")) {return true;}return false;}
}

也可以将注解放在类上面,满足注解条件的类,这个类中的bean才会生效。

@Configuration
// 满足该条件,这个类的bean才会生效
@Conditional(value = LinuxCondition.class)
public class MainConfig {}

@Import

快速向容器中导入一个组件,使用@Import向容器中注册组件有三种方法,后两种方法在 Spring 底层源码用的非常多需要注意

Class<?>[] value():需要向容器中导入的类
  1. @Import直接导入;

    @Configuration
    @Import(value = {Dog.class, Person.class})
    public class MainConfig {}
    

    直接导入Dog和Person bean对象到IOC容器中。

  2. ImportSelector:返回需要导入组件的全类名数组;
    @Configuration
    @Import(value = MyImportSelector.class)
    public class MainConfig {}public class MyImportSelector implements ImportSelector {/*** 将Dog和Person bean对象添加进IOC容器* @param annotationMetadata:当前标注@Import注解类的所有注解信息* return:导入容器中的组件全类名*/@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 默认返回一个空的字符串数组,返回null会报空指针异常return new String[]{"com.kiger.springboot.bean.Dog","com.kiger.springboot.bean.Person"};}
    }
    
  3. ImportBeanDefinitionRegistrar:手动注册Bean到容器中
    @Configuration
    @Import(value = MyImportBeanDefinitionRegistrar.class)
    public class MainConfig {}public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {/*** AnnotationMetadata:当前类的注解信息* BeanDefinitionRegistry:BeanDefinition注册类*    把所有需要添加到容器中的bean*    调用BeanDefinitionRegistry.registerBeanDefinition手工注册进来*/@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 判断BeanDefinitionRegistry是否存在Dog bean对象,如果存在就把 Person注册到容器中boolean definition = registry.containsBeanDefinition("dog");if (definition) {RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Person.class);registry.registerBeanDefinition("person", rootBeanDefinition);}}
    }
    

FactoryBean

使用FactoryBean来注册组件,需要实现FactoryBean接口。

@Configuration
public class MainConfig {@Beanpublic DogFactoryBean dogFactoryBean() {return new DogFactoryBean();}
}// 创建一个Spring定义的FactoryBean
public class DogFactoryBean implements FactoryBean<Dog> {/*** 返回一个Dog对象,这个对象会添加到容器中*/@Overridepublic Dog getObject() throws Exception {return new Dog();}/*** 返回对象类型*/@Overridepublic Class<?> getObjectType() {return Dog.class;}/*** 创建的bean对象是否单例*  - true:单实例*  - false:多实例,每次获取都会调用方法创建*/@Overridepublic boolean isSingleton() {return false;}
}

注意:使用IOC容器获取FactoryBean时,默认获取到的是getObject()方法所创建的bean对象。想要获取FactoryBean对象,可以在id前加 &(&DogFactoryBean)

小总结

通过上面的注解学习我们可以知道将一个组件注册进IOC容器可以有四种方法:

  1. 包扫描+组件标注
    @Controller/@Service/@Repository/@Component
  2. @Bean:导入第三方包里面的组件
    自定义一些少量的组件
  3. @Import:快速向容器中导入组件
  4. 使用Spring提供的FactoryBean(工厂Bean)

二、生命周期

bean 的生命周期:创建->初始化->销毁
初始化:

  • 单实例bean:在容器启动时进行创建完成并属性赋值之后进行初始化;
  • 多实例bean:每一次获取时创建并初始化。

销毁:

  • 单实例bean:关闭容器时,容器会销毁bean实例;
  • 多实例bean:容器只负责创建,不会进行bean实例的销毁,可自行调用销毁方法。

initMethod/destroyMethod

使用@Bean注解指定bean的初始化和销毁方法。

@Bean(initMethod = "init", destroyMethod = "destroy")
public Dog dog() {return new Dog();
}

init/destroy,可在Dog类中实现。

bean实现InitializingBean/DisposableBean接口

Spring提供了InitializingBean/DisposableBean两个接口,bean实现两个接口,就可以在bean创建完成/关闭容器,容器会调用实现的方法

@Component
public class Cat implements InitializingBean, DisposableBean {public Cat() {System.out.println("cat constructor..");}// 在bean创建完成并且属性赋值完成之后调用@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("cat init..");}// 单实例bean在关闭容器时调用@Overridepublic void destroy() throws Exception {System.out.println("cat destroy..");}
}

@PostConstruct/@PreDestroy

由JSR250提供的方法注解。

@Component
public class Cat {public Cat() {System.out.println("cat constructor..");}// 在对象创建并属性赋值完成之后@PostConstructpublic void init() {System.out.println("cat init..");}// 在容器移除对象之前@PreDestroypublic void destroy() {System.out.println("cat destroy..");}
}

BeanPostProcessor

BeanPostProcessor:后置处理器对bean对象初始化前后进行后置处理。

// 对容器中的每一个bean对象的初始化都有效
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {/*** 在bean对象的所有初始化方法之前进行处理* @param bean:容器刚创建好的bean实例* @param beanName:bean实例的名字* @return Object:可以直接返回bean实例,也可以包装之后进行返回*/public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}// 在bean对象的所有初始化方法完成之后进行处理public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}
}

对容器中的每一个bean对象的初始化都有效。

从源码角度解释为什么初始化是在bean对象属性赋值完成之后进行的

在源码AbstractAutowireCapableBeanFactory类 doCreateBean方法中有下面代码块:

通过注解可以得到这个代码块是初始化bean对象实例,但是在调用initializeBean方法之前调用了populateBean方法,这个方法的官方注释为:

Populate the bean instance in the given BeanWrapper with the
property values from the bean definition.

大致意思就是将bean中定义的属性值填充给bean实例。

从源码角度解释 BeanPostProcessor 实现原理

postProcessBeforeInitialization()方法加上断点进行debug,可以在源码AbstractAutowireCapableBeanFactory类 initializeBean方法中看到:

红色标注的这三处分别是调用初始化方法前后置处理方法、初始化方法、初始化方法之后调用后置处理方法。

applyBeanPostProcessorsBeforeInitialization方法中会调用所有的BeanPostProcessor的处理方法:

这也是BeanPostProcessor实现原理。

三、属性赋值

@Value

在字段上标注@Value注解可以为该字段赋值,该注解有三种赋值方式:

  1. 基本数值;
  2. SpEL:#{ };
  3. &{ }:获取配置文件的值。(在springboot中常用)
@Value("jimi")
private String name;
@Value("#{18-10}")
private Integer age;
@Value("${cat.sex}")
private String sex;// 配置文件 application.yml
cat:sex: man

@PropertySource

导入外部配置文件,将配置文件中的值加载到环境变量中,可以使用上面的@Value(${})进行获取 k/v 的值。

String[] value():配置文件路径。- 可以指定 classpath:类路径/file:文件路径

将类路径下的 application.yml 资源文件加载到环境变量中。

@Configuration
@PropertySource(value = {"classpath:application.yml"})
public class MainConfig {}

四、自动装配

@Autowired(Spring注解)

这个注解是根据BeanPostProcessor后置处理器来实现的,原理在之前已经讲过了。

依赖注入

boolean required():默认为true,必须要找到指定的组件,否则报错- false:没找到就跳过,不会报错

举例:一般在Controller层会注入一个Service层的对象来调用服务方法。

@Controller
public class controller {@Autowired(required=false) // 即使没找到也不会报错private service ser;
}

@Autowired 自动装配规则:

  1. 默认按照类型去容器中找对应的组件;

    applicationContext.getBean(serice.class);
    
  2. 如果找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找;
    applicationContext.getBean("ser");
    
  3. 使用@Qualifier指定需要装配的组件id,而不是属性名;
    @Qualifier("ser")
    @Controller
    public class controller {@Autowiredprivate service ser;
    }
    
  4. @Primary在多个相同类型组件中,在其中一个组件上标注该注解,在加载时容器会首选加载该组件;(需要在没有明确指定的情况下)
    @Bean
    @Primary
    public Cat cat() {return new Cat();
    }
    
  5. @Autowired 可以标注在构造器、方法、参数、属性,标注在构造器和方法上,会自动调用该方法,并且从IOC容器中获取参数的实例。
    标注在构造器上,IOC容器在创建该bean时会调用标注的构造器
    @Bean标注的对象参数默认从容器中加载,省略了@Autowired注解
    

@Resource/@Inject(Java规范)

@Resource:由JSR250定义,默认按照组件名称进行装配;

String name():指定装载组件名称,相当于@Qualifier
  • 没有@Primary的功能;
  • 没有@Autowired(required = false)的功能;

@Inject:由JSR330定义,和@Autowired功能一样,但是需要导入javax.inject的包,没有 required = false 的功能。

Aware注入Spring底层组件

在一些类中如果想要使用Spring的一些底层组件,Aware提供了这些底层组件的接口,我们只需要实现这些接口方法就可以获取这些底层组件。

举例:获取ApplicationContext组件。

@Component
public class Cat implements ApplicationContextAware {// 定义一个ApplicationContext对象private ApplicationContext applicationContext;// 通过该接口方法将ApplicationContext注入到Cat类中public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}
}

每一个底层组件的Aware接口都会有对应的AwareProcessor来进行后置处理。

@Profile

指定在哪个环境的情况下才能被注册到容器中,被标注的组件只有在对应环境激活的情况下才能注册进容器,默认是default。(一般用于一些数据源的切换)

举例:Cat bean对象在测试环境下注册进容器。

@Profile("test") // dev/prod
@Bean
public Cat cat() {return new Cat();
}

那么,如何激活环境程序运行在某种环境呢?

  1. 命令行参数(虚拟机参数栏添加)

    -Dspring.profiles.active=test
  2. 代码方式
    // 1.创建IOC容器
    AnnotationConfigApplicationContext applicationContext =new AnnotationConfigApplicationContext();
    // 2.激活环境 - 可以激活多个环境
    applicationContext.getEnvironment().setActiveProfiles("test", "dev");
    // 3.注册主配置类
    applicationContext.register(MainConfig.class);
    

五、AOP【动态代理】

指在程序运行期间动态的将某段代码加入到指定方法位置进行运行的编程方式。

①业务实现AOP流程

1.先定义一个业务逻辑类、切面类并使用@Component加入到容器

业务逻辑类:

// 业务逻辑类
public class MathCalculator {// 该方法作为切入点public int div(int i, int j) {System.out.println("MathCalculator div...");return i / j;}
}

切面类:

// 一定要在切面类上标注@Aspect注解,告诉Spring那个是切面类
@Aspect
public class LogAspect {/*** 抽取公共的切入点表达式:指定在那个方法切入* - 本类引用该表达式:pointCut() 直接写方法名* - 其他切面类引用:com.kiger.aop.LogAspect.pointCut() 方法全名*///    @Pointcut("execution(public int com.kiger.aop.MathCalculator.div(int, int))") 指定方法// MathCalculator类所有方法,参数类型不限@Pointcut("execution(public int com.kiger.aop.MathCalculator.*(..))")public void pointCut() {}@Before("pointCut()")public void logStart(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("除法 " + methodName +" 运行...参数列表是:{" + Arrays.asList(args) + "}");}@AfterReturning(value = "pointCut()", returning = "result")// JoinPoint参数一定要出现在参数表的第一位public void logReturn(JoinPoint joinPoint, Object result) {System.out.println("@AfterReturning 正常返回...运行结果:" + result);}@AfterThrowing(value = "pointCut()", throwing = "exception")public void logException(Exception exception) {System.out.println("@AfterThrowing 除法异常...异常信息:" +exception.getMessage());}
}

2.在配置类中加@EnableAspectJAutoProxy【开启基于注解的AOP模式】

②AOP原理

1.@EnableAspectJAutoProxy 做了什么?

2.AnnotationAwareAspectJAutoProxyCreator 这个组件有什么作用?

先插入 AnnotationAwareAspectJAutoProxyCreator 类图:

可以看到 AnnotationAwareAspectJAutoProxyCreator 实现了两个接口:
SmartInstantiationAwareBeanPostProcessor -> 后置处理器
BeanFactoryAware -> 自动装配 BeanFactory

在前面已经分析了这两个接口的功能,那么我们就在从父类开始找到实现相应接口的方法打上断点进行debug调试,主要的接口方法如下:
前置通知:Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
后置通知:boolean postProcessAfterInstantiation(Object bean, String beanName)
装配BeanFactory:void setBeanFactory(BeanFactory beanFactory)

于是,我们就在下面的类中打上断点进行debug调试来探究组件的功能:


AbstractAutoProxyCreator



↑继承
AbstractAdvisorAutoProxyCreator

↑继承
AnnotationAwareAspectJAutoProxyCreator

在分析 AnnotationAwareAspectJAutoProxyCreator 调用方法之前,我们先看一下 AnnotationAwareAspectJAutoProxyCreator 是如何被创建并注册进 BeanFactory:

了解了 AnnotationAwareAspectJAutoProxyCreator(后置处理器) 的创建和注册的过程,接下来我们来探究 AnnotationAwareAspectJAutoProxyCreator (后置处理器)什么时候起作用、都做了些什么:

经过上面的流程图我们可以知道:
AnnotationAwareAspectJAutoProxyCreator 这个后置处理器会在创建 bean 之前进行拦截返回新的代理对象,和创建之后进行增强返回新的代理对象。

上面已经大致了解了AOP的原理,接下来继续探究执行目标方法这些通知方法是如何被调用的?

上面流程图分析了拦截器链的调用过程,通过拦截器链可以保证通知方法与目标方法的执行顺序。

③AOP小结

在业务逻辑中添加一个AOP切面非常容易,可以理解AOP实现原理还是比较困难需要进行不断的源码调试来探究在这个过程中都做了什么,接下来对AOP原理做一个整体的总结:

  1. @EnableAspectJAutoProxy 开启AOP功能;

  2. @EnableAspectJAutoProxy 向容器中注册了一个组件 AnnotationAwareAspectJAutoProxyCreator;

  3. AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器;

  4. bean 的创建流程:
    ① registerBeanPostProcessors 注册后置处理器,创建 AnnotationAwareAspectJAutoProxyCreator
    ② finishBeanFactoryInitialization 初始化剩余的单实例 bean

    • 创建业务逻辑组件和切面组件
    • AnnotationAwareAspectJAutoProxyCreator 拦截创建组件的创建
    • 在组件创建完成之后,判断组件是否需要增强
      • 是:将切面方法包装成增强器(Advisor),给业务逻辑对象创建一个代理对象(cglib)
  5. 执行目标方法
    ① 代理对象执行目标方法
    ② 使用 CglibAopProxy.intercept() 进行拦截

    • 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
    • 利用拦截器链式机制,依次进入每一个拦截器进行执行
    • 过程:
      正常执行:前置通知 》目标方法》后置通知 》返回通知
      出现异常:前置通知 》目标方法》后置通知 》异常通知

六、声明式事务

@Transactional

SpringBoot 中只需要在 service 类或 service 方法上加上 @Transactional 用来保证事务的一致性,在 service 方法中可能会调用多个 Dao 方法,用来保证多个调用要么成功,要么回滚。

@Service
public class UserService {@Autowiredprivate UserDao userDao;@Transactionalpublic void inserUser() {userDao.insert();// otherDao.xxx();int age = 10/0;}
}

声明式事务原理小议

在 Spring 中想要激活声明式事务就需要在配置类上加上@EnableTransactionManagement 注解:

查看源码得知TransactionManagementConfigurationSelector向容器中添加了两个组件AutoProxyRegistrarProxyTransactionManagementConfiguration

默认 adviceMode=PROXY,接下来分析这两个组件都做了什么:

AutoProxyRegistrar

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar向容器中注册了一个InfrastructureAdvisorAutoProxyCreator组件:

InfrastructureAdvisorAutoProxyCreator 做了什么?
通过源码可以发现InfrastructureAdvisorAutoProxyCreator和上文讲的AnnotationAwareAspectJAutoProxyCreator非常相似,利用后置处理器机制在对象创建之后,包装对象,返回一个代理对象(包装了增强器),代理对象执行方法利用拦截器链进行调用,具体过程可以查看源码。

ProxyTransactionManagementConfiguration

向容器中注册事务增强器BeanFactoryTransactionAttributeSourceAdvisor

  • 事务增强器需要事务注解信息,导入AnnotationTransactionAttributeSource解析事务注解
  • 事务拦截器TransactionInterceptor保存了事务属性信息、事务管理器,它是一个MethodInterceptor(代理对象会在拦截器链调用该拦截器的invoke方法):
    1. 先获取事务相关属性
    2. 在获取PlatformTransactionManager,如果没有事先指定qualifier - 指定的事务管理器属性,最终会从容器中按照类型获取PlatformTransactionManager
    3. 执行目标方法
    如果异常,获取到事务管理器,利用事务管理回滚这次操作;
    如果正常,利用事务管理器,提交事务;

小结

通过AutoProxyRegistrar向容器中注册组件InfrastructureAdvisorAutoProxyCreator,这个组件在业务类方法对象创建之后通过ProxyTransactionManagementConfiguration添加的事务拦截器TransactionInterceptor将拦截器封装在对象中返回一个代理对象,代理对象执行目标方法之后,会调用拦截器链中的事务拦截器方法对事务进行处理(提交/回滚)。

七、扩展原理

1.BeanFactoryPostProcessor

BeanFactory 的后置处理器,在 BeanFactory 标准初始化之后调用,所有的 BeanDefinition 已经保存加载到 BeanFactory,但是 bean 的实例还没有创建。

1.在 IOC 容器创建对象,会在refresh()方法中调用invokeBeanFactoryPostProcessors(beanFactory)方法;

2.从 BeanFactory 中找到所有类型是 BeanFactoryPostProcessor的组件,并根据实现不同接口的优先级来分到不同的集合;
3.不同优先级的集合执行BeanFactoryPostProcessor接口方法。

遍历BeanFactoryPostProcessor集合,并执行接口方法postProcessBeanFactory()

2.BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor的子类接口,定义了postProcessBeanDefinitionRegistry()方法(在所有 BeanDefinition 将要被加载,bean 实例还未创建的时候执行),优先于BeanFactoryPostProcessor执行,利用BeanDefinitionRegistryPostProcessor给容器中在额外注册一些 BeanDefinition。

1.在 IOC 容器创建对象,会在refresh()方法中调用invokeBeanFactoryPostProcessors(beanFactory)方法;

2.可以发现和BeanFactoryPostProcessor执行的是同一个方法,但是在BeanFactoryPostProcessor之前执行invokeBeanDefinitionRegistryPostProcessors()方法,从 BeanFactory 中找到所有类型是 BeanDefinitionRegistryPostProcessor的组件,并根据实现不同接口的优先级来分到不同的集合;

3.不同优先级的集合执行BeanDefinitionRegistryPostProcessor接口方法。
遍历BeanDefinitionRegistryPostProcessor集合,并执行接口方法postProcessBeanDefinitionRegistry()

4.接下来会执行BeanDefinitionRegistryPostProcessor实现的父类BeanFactoryPostProcessor接口的方法postProcessBeanFactory()
5.invokeBeanFactoryPostProcessors()方法后半段是从容器中找到BeanFactoryPostProcessor组件,然后依次调用postProcessBeanFactory()方法(就回到了上面 BeanFactoryPostProcessor 原理)。

3.Spring容器创建流程

下面的流程图分析了SpringIOC容器的创建过程:

因为流程图太大无法上传,想要了解的可以在百度云下载
链接: https://pan.baidu.com/s/1WR6DMo_SOtiARaYmesaarQ
提取码: 3kiy

小结:
1.Spring在启动时,先保存所有注册进来的 bean 定义信息(XML、@Service、@Component、@Bean…)
2.Spring会在合适的时机创建这些 bean

  • 用到这个 bean 的时候,利用getBean()方法,创建以后保存在容器中
  • 统一创建剩下的所有 bean 的时候,finishBeanFactoryInitialization(beanFactory)

3.后置处理器:BeanPostProcessor

  • 每一个 bean 创建完成,都会使用各种后置处理器进行处理,来增强 bean 的功能;
    AutowiredAnnotationBeanPostProcessor:处理自动注入
    AnnotationAwareAspectJAutoProxyCreator:AOP功能
    AsyncAnnotationBeanPostProcessor:异步处理

4.事件驱动模型:
ApplicationListener:事件监听器
ApplicationEventMuticaster:事件派发器

八、Spring异步请求

这里分享一篇博客:SpringBoot中异步请求和异步调用
非常清晰的讲解了如何应用 Servlet3.0 的异步请求以及整合SpringMVC和使用。

Spring注解开发【源码分析】相关推荐

  1. Spring Developer Tools 源码分析:二、类路径监控

    在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...

  2. Spring IOC 容器源码分析系列文章导读

    1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...

  3. Spring IOC 容器源码分析 - 填充属性到 bean 原始对象

    1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...

  4. Spring IOC 容器源码分析 - 创建原始 bean 对象

    1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...

  5. Spring IOC 容器源码分析 - 创建单例 bean 的过程

    1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...

  6. Spring IOC 容器源码分析 - 获取单例 bean

    1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...

  7. Spring IOC 容器源码分析系列文章导读 1

    1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...

  8. Spring Core Container 源码分析七:注册 Bean Definitions

    前言 原本以为,Spring 通过解析 bean 的配置,生成并注册 bean defintions 的过程不太复杂,比较简单,不用单独开辟一篇博文来讲述:但是当在分析前面两个章节有关 @Autowi ...

  9. Spring IOC 容器源码分析

    Spring IOC 容器源码分析 创建时间: 2017-11-15 00:00:00 [TOC] Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring ...

  10. Spring IOC 容器源码分析 - 余下的初始化工作

    1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...

最新文章

  1. 帝国cms7.5多终端刷新单条内容信息时不起作用的解决方法
  2. python对XML的解析
  3. Django中自定义实现RESTful API
  4. 外梯度—lhMorpGradientOut
  5. sklearn线性回归详解
  6. c语言开发破解pdf软件,ARM处理器与C语言开发应用(第2版) PDF
  7. Win10,Win7,WinServer2012,WinServer2008内存最大支持
  8. 724A - CAN总线
  9. 在配置使用Membership或其他的Providers的ASP.NET2.0时一定要设置applicationName属性
  10. 最全的常用正则表达式大全——包括校验数字、字符、一些特殊的需求等等
  11. 手把手教你在VM虚拟机上安装windows11
  12. TAOCP-READING-1-5
  13. 能直接替代替换RC522/CV520的13.56MHz高频读写芯片,太棒了
  14. c 语言试题及解析,C语言试题及答案解析.pdf
  15. UI控件和代理为什么使用weak
  16. dfs应用,迷宫地图解救小哈
  17. CRISPR基因编辑技术获诺奖,人类的福音还是灾难?
  18. 机器字长、存储字长、存储单元的个数、存储容量
  19. 树莓派超详细基础开发教程
  20. 几种常见代码管理工具比较(2009)

热门文章

  1. ISO Standards
  2. 你对ISO了解多少!
  3. Word文件无法正常打开(更新了Office365之后 .docx文件全部变成了 Office Open XML 格式)
  4. 【技术分享】基于编码注入的对抗性NLP攻击
  5. 强化学习的状态值函数与状态动作值函数
  6. php实现ps修图,ps人像怎么快速修图
  7. 拳皇97模拟器没有换面
  8. 如何清空c盘只剩系统_教你如何删除C盘无用文件,确保系统畅快
  9. 人类面临第二次挑战 阿法狗要打星际2了
  10. 大数据概念解析:分布式计算与服务器集群