Spring 中定义(生成)Bean的方式
声明式
- xxx.xml 定义Bean 定义
<bean id = '' class= ''>
结合 ClasspathXmlApplicationContext
- @Compoent
集合 @CompoentScan(basepackage = ''),确保被spring扫描到
- @Bean
结合配置类使用,AnnotionConfigApplicationContext
编程式
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition()
beanDefinition.setBeanClass(xxx.class);
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.registerBeanDefinition("beanname", beanDefinition);
applicationContext.refresh();
- 实现 FactoryBean接口
- Supplier
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.registerBeanDefinition("beanname", new Supplier<Object>() {
@Override
public Object get() {
//返回指定对象
Object o = new Object();
return o;
}
});
Spring 相关容器
单例相关
- 单例
- 原型(多例)
- 单例池(为实现单例存在,保存单例数据) ConcurrentHashMap
BeanFactory
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("userName", new Object());
beanFactory.getBean("userName", xxx.class);
ApplicationContext
继承了 BeanFactory 等n多接口,为集大成者
ClassPathXmlApplicationContext
public ClassPathXmlApplicationContext(String configLocation)
系统在 ClassPath 路径下查找对应名字的文件
可刷新
FileSystemXmlApplicationContext
public FileSystemXmlApplicationContext(String configLocation)
可以在指定的绝对路径中加载对应的配置文件
AnnotationConfigApplicationContext
public AnnotationConfigApplicationContext(Class<?>... componentClasses)
参数可以传入类
不可🙅刷新
Spring Bean 生命周期
- 解析类扫描包,获取BeanDefinition
- 如果有多个构造器,要推断构造方法
- 确定好构造方法后,实例化一个对象
- 对对象中@Autowired注解的属性进行属性填充
- 调用aware方法,比如BeanNameAware, BeanFactoryAware
- 调用BeanPostprocessor的初始化前的方法,处理@PostConstruct注解
- 调用初始化方法,处理initializingBean 接口
- 调用BeanPostprocessor的初始化后的方法,这里会进行AOP
- 如果Bean对象是单例的,则放入单例池
- Bean对象的使用
- Bean对象的销毁
Spring Bean 作用域
- singleton: 默认每个容器中只有一个Bean的实例
- prototype: 每一个Bean 请求一个实例
- request: 每个Http请求中创建一个单例对象
- session: 每个Session中有一个Bean的实例
BeanNameAware 这个接口做了什么
- 让实现这个接口的bean知道自己在spring容器里的名字
Bean 单例问题
如果在Bean中声明了成员变量,并有多个线程对其进行读写操作,则此Bean
不为线程安全
但是如果把成员变量声明在方法内部,则为线程安全
Spring 如何处理线程安全的问题
- 修改Bean作用域为原型模式
- 使用ThreadLocal 做线程隔离
- 加锁保证线程安全
- 成员变量声明在方法内部
@Value使用
- 作为字符串使用
@Value("张三")
private String name;
- 取出配置文件【properties】中的值(在运行环境变量里面的值)
@Value("${person.nickName}")
private String nickName;
- spring 表达式
@Value("#{20-2}")
private Integer age;