Applicationcontext与BeanFactory区别
applicationcontext对BeanFactory实现额外增强 1.applicationcontext主动添加Bean(工厂)处理器 来完成扫包2.applicationcontext主动添加bean处理器 ----依赖注入@Autowired 3.applicationcontext主动初始化单例对象BeanFactory----bean定义信息、单例池
Bean工厂处理器与Bean后置处理器之间有哪些区别
1.Bean工厂处理器是在实例化Bean之前执行,例如 Spring中ConfigurationClassPostProcessor 解析 componentScan , Bean , Import ,ImportResource 注册Bean信息,可以通过工厂Bean处理器修改Bean的定义信息。2.Bean后置处理器 是在 init前后执行 ,可以修改Bean对象为代理对象 从而对我们方法实现增强。
SpringBean的生命周期
四阶段:实例化->属性赋值->初始化->销毁
bean定义阶段-BeanDifinition(可单独作为一个章节去了解)
1.元信息配置
面向资源(xml)
xml方式配置、Propeties配置(具体可以细分去了解,相关的定义bean和注册bean)
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 实例化 基于properties资源的 BeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
String location = "/META-INF/dependency-lookup-context.xml";
// 加载 Properties 文件,用resource的方式可以避免乱码
// 指定字符编码 UTF-8
Resource resource = new ClassPathResource(location);
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
int beanNumbers = beanDefinitionReader.loadBeanDefinitions(encodedResource);
System.out.printf("已加载的 BeanDefinition 数量: %d%n", beanNumbers);
// 通过 bean id 和类型进行依赖查找
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
}
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
// 实例化 基于properties资源的 BeanDefinitionReader
PropertiesBeanDefinitionReader beanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);
String location = "/META-INF/user-bean.properties";
// 加载 Properties 文件,用resource的方式可以避免乱码
// 指定字符编码 UTF-8
Resource resource = new ClassPathResource(location);
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
int beanNumbers = beanDefinitionReader.loadBeanDefinitions(encodedResource);
System.out.printf("已加载的 BeanDefinition 数量: %d%n", beanNumbers);
// 通过 bean id 和类型进行依赖查找
User user = beanFactory.getBean("user", User.class);
System.out.println(user);
}
面向注解
- @component
- @import
- @bean
面向API
命名方式
可以指定bean的名称
BeanDefinitionBuilder#registerBeanDefinition
非命名方式
不指定bean的名称,用spring默认的bean名称生成
BeanDefinitionReaderUtils.registerWithGeneratedName
配置类方式
AnnotatedBeanDefinitionReader.register()
2.元信息解析
针对资源的解析
有两个解析器XmlBeanDefinitionReader和 PropertiesBeanDefinitionReader他们都继承于AbstractBeanDefinitionReader
针对于注解的解析
有AnnotatedBeanDefinitionReader他不继承与任何类,因为注解的扫描和资源的扫描是完全不同的
AnnotationConfigApplicationContext上下文中默认的reader就是AnnotatedBeanDefinitionReader
3.元信息注册
核心代码
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
// 这里会对MethodOverrides做检查
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 判断是否有同名的bean被注册过了
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 是否允许直接进行负载
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
// 因为beanDefinitionMap是全局变量,这里定会存在并发访问的情况
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
4.元信息合并
基本解答
1.首先是实例化Bean,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚末初始化的依赖时,容器就会调用doCreateBean()方法进行实例化,实际上就是通过反射的方式创建出一个bean对象
2.Bean实例创建出来后,接着就是给这个Bean对象进行属性填充,也就是注入这个Bean依赖的其它bean对象
属性填充完成后,进行初始化Bean操作,初始化阶段又可以分为几个步骤:
3.1执行Aware接口的方法
3.2.Spring会检测该对象是否实现了xxxAware接口,通过Aware类型的接口,可以让我们拿到Spring容器的些资源。如实现
3.3.BeanNameAware接口可以获取到BeanName,实现BeanFactoryAware接口可以获取到工厂对象BeanFactory等
3.4.执行BeanPostProcessor的前置处理方法postProcessBeforelnitialization(),对Bean进行一些自定义的前置处理
3.5.判断Bean是否实现了InitializingBean接口,如果实现了,将会执行lnitializingBean的afeterPropertiesSet()初始化方法;
3.6.执行用户自定义的初始化方法,如init-method等;
3.7.执行BeanPostProcessor的后置处理方法postProcessAfterinitialization()
初始化完成后,Bean就成功创建了,之后就可以使用这个Bean, 当Bean不再需要时,会进行销毁操作,
3.8首先判断Bean是否实现了DestructionAwareBeanPostProcessor接口,如果实现了,则会执行DestructionAwareBeanPostProcessor后置处理器的销毁回调方法
3.8其次会判断Bean是否实现了DisposableBean接口,如果实现了将会调用其实现的destroy()方法
3.9最后判断这个Bean是否配置了dlestroy-method等自定义的销毁方法,如果有的话,则会自动调用其配置的销毁方法;
Spring相关注解
@Controller - 用于 Spring MVC 项目中的控制器类。
@Service - 用于服务类。
@RequestMapping - 用于在控制器处理程序方法中配置 URI 映射。
@ResponseBody - 用于发送 Object 作为响应,通常用于发送 XML 或 JSON 数据作为响应。
@PathVariable - 用于将动态值从 URI 映射到处理程序方法参数。
@Autowired - 用于在 spring bean 中自动装配依赖项。
@Qualifier - 结合@Autowired 注解一起使用,以避免在存在多个 bean 类型实例时出现混淆。
而在@Autowired注解中加入(required = false)属性后,表示该注入是可选的。如果当前上下文中没有找到与要求匹配的Bean,则不会抛出异常,而只是简单地跳过这个注入。这样可以避免由于缺少某些Bean导致应用程序启动失败的情况发生。
需要注意的是,当设置(required = false)属性后,如果没有找到匹配的Bean,则被注入的字段、构造函数或方法参数会被设置为null。因此,在使用这个属性时,需要确保代码对这种情况进行了处理,以避免空指针异常等运行时错误的发生。
@Autowired(required = false)
private Date date ;
@Autowired
@Qualifier("birth")
private Date birthday ;
@Scope - 用于配置 spring bean 的范围。
@Scope("singleton"):默认值为singleton,表示在整个应用程序中只创建一个Bean实例。适用于无状态的Bean,例如工具类。
@Scope("prototype"):每次请求都会创建一个新的Bean实例。适用于有状态的Bean,例如用户登录信息等。
@Scope("session"):在用户会话期间只创建一个Bean实例,不同用户之间的Bean实例是独立的。适用于需要保存用户状态的Bean,例如购物车。
@Scope("request"):在HTTP请求期间只创建一个Bean实例,不同请求之间的Bean实例是独立的。适用于需要处理HTTP请求的Bean,例如REST API。
@Scope("globalSession"):在全局会话期间只创建一个Bean实例,通常用于基于Portlet的Web应用程序。
@Configuration,@ComponentScan 和 @Bean - 用于基于 java 的配置。 在下面的示例中,@ComponentScan注解指定了需要扫描的两个包路径,即"com.example.package1"和"com.example.package2"。Spring会扫描这两个包下的所有组件,并将其作为bean注册到应用程序上下文中。
此外,@ComponentScan注解也可以与其他注解一起使用,如@EnableAutoConfiguration注解和@SpringBootApplcation注解。
@Configuration
@ComponentScan(basePackages = {"com.example.package1", "com.example.package2"})
public class AppConfig {
// 配置bean
}
@Aspect,@Before,@After,@Around,@Pointcut - 用于切面编程(AOP)。