说明
有段时间看Spring源码,做的一些笔记,防止丢失,放了上来。
比较琐碎,见谅。
流程相关
常见类名含义
BeanDefinitionReader (从xml或者注解中读取Bean的定义信息)
BeanFactory(工厂)
FactoryBean(拓展的接口,可以创建和管理BeanFactory中的Bean)
ApplicationContextAware(ApplicationContextAware 通过它Spring容器会自动把上下文环境对象调用ApplicationContextAware接口中的setApplicationContext方法。 用户可以在这个方法中获取上下文环境)
Aware 在应用程序中,想要使用Spring的组件,可以实现这个接口,Spring会通过回调式的方法,把功能注入进去。
populateBean 表示给Bean属性赋值
BeanPostProcessor:bean后置处理器,bean创建对象初始化后进行拦截工作的。
BeanFactoryPostProcessor:beanFactory的后置处理器;在BeanFactory标准初始化之后调用;所有的bean定义已经加载到beanFactory,但是bean的实例还未创建。
BeanDefinitionRegistryPostProcessor 可以修改bean的定义信息,在bean定义信息已经被加载,但是还没实例化的时候生效
BeanDefinitionRegistry Bean定义信息的保存中心,BeanFactory就是按照BeanDefinitionRegistry里面保存的每一个Bean定义信息创建bean实例
RootBeanDefinition 用来自定义bean的定义信息吗,也可以用BeanDefinitionBuilder来构建BeanDefinitionBuilder.rootBeanDefinition( class)
ApplicationListener 用来监听Spring容器事件,ContextRefreshedEvent用来监听刷新的事件,ContextCloesedEvent用来监听容器关闭事件。
refresh流程
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//预处理
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//创建一个工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//初始化工厂
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//空方法,未实现
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//执行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//初始化,国际化相关的组件
initMessageSource();
// Initialize event multicaster for this context.
//初始化事件派发器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//未实现,留给子类的
onRefresh();
// Check for listener beans and register them.
//将容器里面所有ApplicationListener注册进来,并且添加到事件派发器中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//BeanFactory初始化剩下来的bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//完成BeanFactory的创建
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
prepareRefresh
刷新前的预处理
prepareBeanFactory
给beanFactory设置参数,做一些初始化工作。
注解相关
1、@Scope
多实例
多实例情况下,ioc容器启动并不会去调用方法创建对象放在容器中。每次获取的时候才会调用,并且创建。
@Scope(scopeName = "prototype")
单实例
启动后,就把对象放到容器中,获取的时候通过map.get获取
@Scope(scopeName = "singleton")
还可以为 request(同一个请求创建一个实例), session(同一个session创建一个实例)
2、@lazy
懒加载,针对于单例模式。添加注解后,对象不会一开始就放在容器内,等第一次获取的时候才回去把他放进容器里。
3、@Conditional
满足条件则生效
@Bean
@Conditional(WindowsConditional.class)
public UserInfo getUserInfo() {
return new UserInfo("小明", 123);
}
@Bean
@Conditional(LinuxConditional.class)
public UserInfo getUserInfo2() {
return new UserInfo("小李", 123);
}
自定义条件
public class WindowsConditional implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
return "Windows 10".equals(environment.getProperty("os.name"));
}
}
4、添加组件
@Bean
向容器中添加组件的一种方式,通常加在第三方包上。
而@Componet 、@Service、@Autowired这些都是加在方法上。
@Import
也是一种导入组件的方法。
可以直接加类名,也可以自定义一个Bean定义类
@Import(User.class)
//@ComponentScan(basePackages = {"com.dayrain"}, includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})})
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class BeanConfig {
@Bean
@Conditional(WindowsConditional.class)
public UserInfo getUserInfo() {
return new UserInfo("小明", 123);
}
@Bean
@Conditional(LinuxConditional.class)
public UserInfo getUserInfo2() {
return new UserInfo("小李", 123);
}
}
Bean定义注册类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Red.class);
registry.registerBeanDefinition("red", rootBeanDefinition);
}
}
FactoryBean
FactoryBean也是拓展容器(向容器内部添加Bean)的一种方法。
具体怎么用呢?
我先定义一个类
public class Color {
}
想通过FactoryBean来把他添加进容器中。所以先定义一个 ColorFactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
//是否是单例
@Override
public boolean isSingleton() {
return true;
}
}
注册FactoryBean
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class BeanConfig {
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
测试
public class Main2 {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanConfig.class);
Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
System.out.println(colorFactoryBean.getClass());
}
}
结果
class com.dayrain.factorybean.Color
虽然@Bean加在FactoryBean上,但实际上ioc容器会调用factoryBean的getObject方法,获取真正需要注入的对象。
5、生命周期
这里的生命周期指的是自定义bean的创建和销毁
方式一:Bean注解
public class Fish {
public Fish() {
System.out.println("买了一条鱼");
}
public void init() {
System.out.println("烹饪");
}
public void eat(){
System.out.println("吃了");
}
}
@Configuration
public class FishConfig {
@Bean(initMethod = "init", destroyMethod = "eat")
public Fish fish(){
return new Fish();
}
}
public class FishMain {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(FishConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
方式二:实现预制接口
public class Bird implements InitializingBean, DisposableBean {
public Bird() {
System.out.println("出生了");
}
@Override
public void destroy(){
System.out.println("走了");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("来了");
}
}
方式三:@PostConstruct和@PreDestory
public class Dog {
public Dog(){
System.out.println("创建");
}
@PostConstruct
public void init(){
System.out.println("初始化");
}
@PreDestroy
public void destroy() {
System.out.println("销毁");
}
}
public class DogMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(DogConfig.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
方式四:BeanPostProcessor
需要实现接口
BeanPostProcessor
postProcessBeforeInitialization 初始化执行之前
postProcessAfterInitialization 初始化执行之后
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization执行了");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization执行了");
return bean;
}
}
但是这么做是对容器内所有的bean都生效。
如果返回值为null,表示后面的BeanPostProcessor都不会执行了
7、@Value
给Bean赋值,加在Bean的属性上
可以是常规值,表达式值( #{} ),引用外部文件值( ${} )
8、@Primary
比如容器中可能会出现多个UserInfo,如果其中一个加上来@Primary,
则Spring在进行自动装配的时候,会优先注入这个Bean。
@Autowired
UserInfo userinfo;
@Resource是不支持@Primary的
9、@Profile
@Profile:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
/**
* Profile:
* Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
*
* 开发环境develop、测试环境test、生产环境master
* 数据源:(/dev) (/test) (/master)
*
* @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
*
* 1) 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
* 2) 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
*
*/
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private String driverClass;
@Profile("default")
@Bean("test")
public DataSource testDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("dev")
public DataSource devDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("master")
@Bean("master")
public DataSource masterDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setDriverClass(driverClass);
return dataSource;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
String driverClass = resolver.resolveStringValue("${db.driverClass}");
this.driverClass = driverClass;
}
}
public class IOCTestProfile {
//1. 使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
//2. 使用代码的方式激活某种环境;
@Test
public void test01() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
//1. 创建一个applicationContext
//2. 设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("dev","master");
//3. 注册主配置类
applicationContext.register(MainConfigOfProfile.class);
//4. 启动刷新容器
applicationContext.refresh();
String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
System.out.println(Arrays.toString(beanNamesForType));
applicationContext.close();
}
@Test
public void test02() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
System.out.println(Arrays.toString(beanNamesForType));
applicationContext.close();
}
}
10、@EventListener
可以监听事件,使用案例
@Component
public class UserService {
@EventListener(classes = {ApplicationEvent.class})
public void listen(ApplicationEvent event) {
System.out.println("UserService.....监听到事件");
}
}
AOP
AnnotationAwareAspectJAutoProxyCreator