一.基本概念
组件:具有一定功能的对象
容器:管理组件(创建、获取、保存、销毁)
IOC:Inversion of Control(控制反转)
- 控制:资源的创建、获取、销毁
- 反转:和传统方式不同
DI:Dependency Injection(依赖注入)
- 依赖:组件的依赖关系
- 注入:通过setter方法、构造器等方式自动注入
二.组件注册
1.主类
运行时返回ioc容器
@SpringBootApplication
public class Demo01Application {
public static void main(String[] args) {
ConfigurableApplicationContext ioc =SpringApplication.run(Demo01Application.class, args);
}
}
使用以下命令获得所有组件名称
String[] beanNames = ioc.getBeanDefinitionNames();
2.bean组件
a.注册bean组件
首先在bean文件夹中创建类(@Data注解为lombok自动补全)
@Data
public class Person {
private String name;
private int age;
private String gender;
}
然后在主类中创建方法,返回该类
加上@Bean(“名字”)注解,此时组件就注册好了,组件名默认是方法名
@Bean
public Person zhangsan() {
Person person = new Person();
person.setName("zhang");
person.setAge(18);
person.setGender("男");
return person;
}
- 组件的创建时期:容器的启动过程中就会创建组件对象
- 组件的默认模式:单例
b.手动获取bean组件
按名字获取bean组件,默认为object对象,需要时可以强转为指定类型
Object zhangsan = ioc.getBean("zhangsan");
按类型获取单一bean组件,默认为原类型,无须强转
Person bean = ioc.getBean(Person.class);
按类型获取所有bean组件,默认为map集合
Map<String, Person> beansOfType = ioc.getBeansOfType(Person.class);
按照类型+名字获取单一bean组件,默认原类型
异常情况:
- 组件不存在,抛异常
- 组件不唯一
- 按类型只获取一个组件,抛异常
- 按名字只获取一个组件,不会抛异常,会返回排在最前面的方法
3.Configuration配置类
@Configuration 标注配置类,可用于配置bean组件
@Configuration
public class PersonConfig {
@Bean
public Person zhangsan() {
return new Person("zhangsan", 20, "男");
}
}
4.SpringMVC分层注解
给人看的,实际都是Component
@Controller控制层
@Service服务层
@Repository持久层
@Component组件
5.ComponentScan组件扫描
@ComponentScan(basePackages = "com.zhang.demo1")
写在配置类上
扫描当前包及其子包,注册了的组件
6.Import导入外部类
外部类无法标注解,只能导入
@Import(xxx.class)
写在配置类上
7.Scope作用域
@Scope("prototype")非单实例
@Scope("singleton")单实例,默认值
@Scope("request")同一请求单实例
@Scope("session")同一会话单实例
8.Lazy懒加载
默认为饿汉式加载,修改为懒汉式加载
@Lazy
标注在@Bean的上方
懒汉加载是指在首次使用时才创建对象实例,而饿汉加载则是在类加载时就创建对象实例。
9.FactoryBean工厂
代替@Bean注解标注组件
适用场景:制造对象复杂的时候
@Component
public class BYD implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new Car();
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
10.Conditional条件注册
@Contitional(xxx.class)
标注在@bean的上方,需要添加一个条件类
public class windowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os").contains("mac");
}
}
此外还有多种特殊条件注解
- @Conditional:这是最基本的条件注解,它可以接受一个或多个Condition接口的实现类作为参数。只有当所有条件都满足时,才会创建或注册Bean。
- @ConditionalOnBean:这个注解用于检查指定的Bean是否存在于Spring容器中。如果存在,则创建或注册当前Bean。
- @ConditionalOnMissingBean:与@ConditionalOnBean相反,这个注解用于检查指定的Bean是否不存在于Spring容器中。如果不存在,则创建或注册当前Bean。
- @ConditionalOnClass:这个注解用于检查指定的类是否存在于类路径中。如果存在,则创建或注册当前Bean。
- @ConditionalOnMissingClass:与@ConditionalOnClass相反,这个注解用于检查指定的类是否不存在于类路径中。如果不存在,则创建或注册当前Bean。
- @ConditionalOnProperty:这个注解用于检查指定的属性是否存在于配置文件中,并且其值是否满足指定的条件。如果满足条件,则创建或注册当前Bean。
- @ConditionalOnResource:这个注解用于检查指定的资源是否存在于类路径中。如果存在,则创建或注册当前Bean。
- @ConditionalOnWebApplication:这个注解用于检查当前应用是否是一个Web应用。如果是,则创建或注册当前Bean。
- @ConditionalOnNotWebApplication:与@ConditionalOnWebApplication相反,这个注解用于检查当前应用是否不是一个Web应用。如果不是,则创建或注册当前Bean。
三.组件注入
1.基本注解
- @Autowired: 注入方式:默认按照类型(byType)进行注入。如果有多个相同类型的Bean,Spring会尝试按照名称(byName)进行注入。如果仍然无法确定唯一的Bean,Spring会抛出异常。 使用场景:适用于大多数情况,尤其是当只有一个匹配的Bean时。
- @Resource: 注入方式:默认按照名称(byName)进行注入。如果没有找到匹配的名称,则按照类型(byType)进行注入。 使用场景:适用于需要明确指定名称进行注入的情况,或者在Java标准库中使用。
- @Qualifier: 注入方式:与@Autowired或@Inject一起使用,用于指定具体要注入的Bean。 使用场景:当有多个相同类型的Bean时,通过指定名称或其他限定符来明确注入的Bean。
- @Primary: 注入方式:当有多个相同类型的Bean时,使用@Primary注解来指定首选的Bean。当没有使用@Qualifier注解时,Spring会优先注入使用@Primary注解的Bean。 使用场景:适用于有多个相同类型的Bean,但希望有一个默认的首选Bean的情况。
2.构造器注入:
@Component
public class dog {
private Person person;
public dog(Person person) {
this.person = person;
}
}
组件中可以根据构造方法的参数自动注入
在参数前可以用@Qualifier
3.xxxAware感知接口
@Component
public class dog implements EnvironmentAware {
@Override
public void setEnvironment(Environment environment) {
}
}
- BeanNameAware:获取Bean的名称。
- BeanFactoryAware:获取BeanFactory实例。
- ApplicationContextAware:获取ApplicationContext实例。
- MessageSourceAware:获取国际化消息源。
- ApplicationEventPublisherAware:获取事件发布器。
- ResourceLoaderAware:获取资源加载器
4.Value属性赋值
加在组件的属性上方
1.直接赋值
@Value("指定值")
2.从配置文件xxx.properties获取值
@Value("${配置文件key}")
设置默认值
以:分割,当取不到cat.name时,默认为Tom
@Value("${cat.name:Tom}")
3.进行计算赋值
@Value("#{10*20}")
4.调用方法赋值
@Value("'zhangsan'.toUpperCase()")
5.静态调用类赋值
@Value("T(java.lang.Math).random()")
5.属性来源
写在类上,注明@Value取值的文件
classpath:从项目路径下找
classpath*:从所有包路径下找
@PropertySource("classpath:application.properties")
6.多环境
在指定环境下加载组件
在类或者方法上标注
@Profile("环境标识,环境标识...")
项目默认为default环境
可以在配置文件中修改激活环境
spring.profiles.active=环境
四、组件生命周期


1.@Bean自定义初始化/销毁方法
在类中定义相关方法
public void initUser() {
System.out.println("初始化---------------");
}
public void destroyUser() {
System.out.println("销毁----------------");
}
@Bean注册为组件时,指明方法
@Bean(initMethod = "initUser", destroyMethod = "destroyUser", name = "myUser")
public Users user() {
return new Users();
}
2.intializingBean,disposableBean接口
intializingBean:在init之前执行
disposableBean:在destory之前执行
@Data
public class Users implements InitializingBean, DisposableBean{
private String name;
private int age;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("初始化");
}
@Override
public void destroy() throws Exception {
System.out.println("销毁");
}
}
3.@PostConstruct,@PreDestory方法
@PostConstruct(构造器后置处理钩子):在intializingBean之前
@PreDestory(销毁预处理钩子):在disposableBean之前
@PostConstruct
public void init(){
System.out.println("PostConstruct");
}
@PreDestroy
public void destroy(){
System.out.println("PreDestroy");
}
4.BeanPostProcessor后置处理器
BeanPostProcessor是一个拦截所有Bean的后置处理器
@Component
public class beanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization====="+beanName);
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName)
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization====="+beanName);
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
将其实现后放到容器中,将拦截所有注册的Bean
@Autowired是如何实现的?
1、专门有一个处理@Autowired注解的AutowiredAnnotationBeanPostProcessor
2、每个Bean创建以后,会调用BeanPostProcessBeforeInitalization方法
3、postProcessBeforeInitialization里面就会利用反射,得到当前Bean的所有属性,利用反射,得到Bean属性上标注的所有注解,看有没有@Autowired注解
4、如果有,去容器中找到这个属性对应的组件(按类型、名字)找到。
5.总结
- @Bean创建对象
- 调用类构造器
- postProcessBeforeInitialization
- @Autowired set属性注入
- PostConstruct
- InitializingBean(afterPropertiesSet属性设置之后)
- init
- postProcessAfterInitialization
- —————–ioc容器创建完毕——————-
- PreDestroy
- DisposableBean
- destroy
补充:@Autowired 是如何实现的?
- 专门有一个处理
@Autowired
注解的AutowiredAnnotationBeanPostProcessor
。 - 每个 Bean 创建以后,会调用
BeanPostProcessor
的postProcessBeforeInitialization
方法。 postProcessBeforeInitialization
里面就会利用反射,得到当前 Bean 的所有属性,利用反射,得到 Bean 属性上标注的所有注解,看有没有@Autowired
注解。- 如果有,去容器中找到这个属性对应的组件(按类型,按名字)找到。
——————-容器篇结束——————–
Comments NOTHING