容器篇
一.基本概念
组件:具有一定功能的对象
容器:管理组件(创建、获取、保存、销毁)
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}")
3.进行计算赋值
@Value("#{10*20}")
4.调用方法赋值
@Value("'zhangsan'.toUpperCase()")
5.静态调用类赋值
@Value("T(java.lang.Math).random()")
设置默认值
以:
分割,当取不到cat.name时,默认为Tom
@Value("${cat.name:Tom}")
5.属性来源
写在类上,注明@Value取值的文件
classpath:从项目路径下找
classpath*:从所有包路径下找
@PropertySource("classpath:application.properties")
6.多环境
在指定环境下加载组件
在类或者方法上标注
@Profile("环境标识,环境标识...")
项目默认为default环境
可以在配置文件中修改
spring.profiles.active=环境
四、组件生命周期
1.
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
5.总结
@Bean创建对象
调用类构造器
postProcessBeforeInitialization
@Autowired set属性注入
PostConstruct
InitializingBean(afterPropertiesSet属性设置之后)
init
postProcessAfterInitialization
-----------------ioc容器创建完毕-------------------
PreDestroy
DisposableBean
destroy
补充:@Autowired 是如何实现的?
-
专门有一个处理
@Autowired
注解的AutowiredAnnotationBeanPostProcessor
。 -
每个 Bean 创建以后,会调用
BeanPostProcessor
的postProcessBeforeInitialization
方法。 -
postProcessBeforeInitialization
里面就会利用反射,得到当前 Bean 的所有属性,利用反射,得到 Bean 属性上标注的所有注解,看有没有@Autowired
注解。 -
如果有,去容器中找到这个属性对应的组件(按类型,按名字)找到。
-----------------容器篇结束--------------------