1. Spring IOC 注解
1. Spring IOC 注解
1.1 装配Bean
BeanFactory是所有IOC容器的父类,ApplicationContext也继承自BeanFactory
public interface BeanFactory {
//前缀
String FACTORY_BEAN_PREFIX = "&";
//以下多个获取bean的方法
Object getBean(String var1) throws BeansException;
<T> T getBean(String var1, Class<T> var2) throws BeansException;
Object getBean(String var1, Object... var2) throws BeansException;
<T> T getBean(Class<T> var1) throws BeansException;
<T> T getBean(Class<T> var1, Object... var2) throws BeansException;
<T> ObjectProvider<T> getBeanProvider(Class<T> var1);
<T> ObjectProvider<T> getBeanProvider(ResolvableType var1);
boolean containsBean(String var1);
//是否单例,默认是
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
//是否是原型
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//获取bean的类型
@Nullable
Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;
//获取bean的别名
String[] getAliases(String var1);
}
Spring会把ApplicationContext的类目录及所有子目录下的组件自动添加到容器中
@Configuration注解的类代表是配置类
@Configuration
public class AppConfig{@Bean(value="admin")
public User adminUser(){
User user = new User();
return user;
}
}
可以通过如下方法测试:
public void test(){
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
//ApplicationContext可以通过类名或者Bean名称两种方式获取bean
User user = context.getBean(User.class);
log.info(user.getUserName());
}
- @Bean注解一个方法,会把方法的返回对象添加到容器中,若没有用value=””指定名称,则会把方法的名称作为该组件的名称。
- Bean在容器中,默认是单例的
自动装配bean到容器(无需@Bean注解)
使用**@Component标明哪个类被扫描进入IOC容器
使用@ComponentScan**标明使用何种策略扫描装配Bean(默认是@ComponentScan注解的类当前目录及其子目录的所有@Component注解的类都自动添加到容器中)。
@SpringBootApplication注解中就有@ComponentScan注解,所以ApplicationContext目录及子目录的组件会自动添加到容器。@Component(“user”)
public class User{@Value(1)
private int id;
@Value("nike")
private String username;
@Value("note1")
private String note;
}
@ComponentScan的扫描策略可指定扫描的包基础路径、过滤条件等。如:
@ComponentScan(basePackages = "xyz.mxlei.base.*",
excludeFilters = {
@Filter(classes={
Service.class})})
1.2 依赖注入
在非常多的bean都装入容器中后,每个bean在容器中都行相互独立的,而在实际应用中需要不同的bean之间进行相互依赖使用。这时候就使用依赖注入的方式实现bean之间的依赖关系。
@AutoWired
根据数据类型type来获取bean,在IOC容器的顶级接口BeanFactory中有相应的getBean方法。
如果@AutoWire注解的对象是接口类型的,当项目中只有一个该接口实现类时正常getBean,当有多个实现类时,会根据对象的名称,通过以bean名称的方式获取bean,若依旧不匹配,则抛出异常。public interface Animal{
}
public class Dog implements Animal{
}
public class Cat implements Animal{
}
@Componment
public class Test{
//由于Animal有两个实现类,以dog名称获取bean
@AutoWired
public Animal dog;
}
- @AutoWired冲突处理
当通过类型获取bean有多个时,可以用1中的处理方法,也可以用@Primary或者@Qualifier两个注解来解决。 @Primary
用来注解bean类,告诉IOC容器,当发现多个同类型bean时,请优先使用我进行注入。@Primary
public class Dog implements Animal{}
但是多个类用@Primary注解时,还会出现不知道如何选择的问题,这时可用@Qualifier
@Qualifier
和@AutoWired结合使用,表示使用名称和类型结合一起来查找bean。@Componment
public class Test{//名称和类型结合一起来查找bean
@AutoWired
@Qualifier("dog")
public Animal animal;
}
带参数的构造方法类的装配
上面中队Test类装配了bean,是基于Test类的构造方法是无参的,假如Test类只有有参构造方法,可通过@AutoWired注解构造方法的参数进行注入。@Componment
public class Test{public Animal animal;
public Test( @AutoWired @Qualifier("dog") Animal animal){
this.animal = animal;
}
}
1.3 Bean的生命周期
bean在@AutoWired注入时才实例化
ComponentScan所定义的包
bean定义保存到BeanDefinition实例中
IOC容器装在Bean定义
创建Bean的实例对象
资源定位
Bean定义
发布Bean定义
实例化
依赖注入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fj3h1911-1578040728960)(https://i.loli.net/2020/01/03/kltDoTObW5IPeKz.png)\]
1.4 使用配置文件配置bean属性
可以用application.properties或application.yaml来配置bean属性。
@compoment注解的类会被扫描添加到IOC容器,这些bean的参数可以在类中赋予初始值也可在配置文件中配置。
application.properties配置User的值
admin.username=mxlei
admin.password=1234@Value配置
@Component
@ConfigurationProperties(“admin”)
public class User{@Value(${
admin.username})
private String username;
@Value(${
admin.password})
private String password;
}
@ConfigurationProperties配置
设置配置文件中的配置名的前缀,自动根据名称来初始化值@Component
@ConfigurationProperties(“admin”)
public class User{private String username;
private String password;
}
@PropertySource指定配置文件
@Component
@ConfigurationProperties(“admin”)
@PropertySouce(value={"classpath:account.properties"}, ignoreResourceNotFound=true)
public class User{
private String username;
private String password;
}
@Conditional条件装配Bean
1.5 Bean的作用域
在IOC容器的顶级接口BeanFactory中,有isSingleton和isPrototype两个方法。分别表示bean在容器中以单例存在和每次获取bean的时候,IOC容器都创建一个新的Bean。在web容器中,存在多种所用域。
作用域类型 | 使用范围 | 描述 |
---|---|---|
singleton | 所有Spring应用 | 默认值,IOC容器只存在单例 |
prototype | 所有Spring应用 | 每当从IOC容器中取出一个bean,则拆改那就一个新的bean |
session | Spring Web应用 | HTTP会话 |
application | Spring Web应用 | Web工程生命周期,完全可用singleton代替 |
request | Spring Web应用 | Web工程单次请求 |
globalSession | Spring Web应用 | 在一个全局的HTTP Session中,一个Bean定义对应一个实例 |
@Scope配置作用域
@Componment
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ScopeBean{}
在ConfigurableBeanFactory中只有singleton和prototype两种作用域,在SpringMVC中可以使用WebApplicationContext来配置其他作用域。
@Componment
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class ScopeBean{
}
1.6 使用@Profile指定bean的配置文件
在实际开发中,有开发环境、测试环境、生产环境等,各个环境下的配置文件经常要求不相同。
@Componment
//使用上图中的application-dev.yml配置bean
@Profile("dev")
public class User{
}
在使用@Profile指定应用环境时,需要配置spring.profiles.active或者spring.profiles.default来指定当前的运行环境。当运行环境符合@Profile配置的环境时才装配bean属性,否则不装配属性。
1.7 使用XML文件配置Bean
在Springboot中推荐使用配置文件properties或者yaml来配置bean,同样也兼容spring中的使用xml文件配置bean。可以使用@ImportResource注解来指定使用xml文件配置bean。
//没有@component
public class User{
}
xml配置文件spring-other.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.s3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframeword.org/schema/beans/spring-beans.xsd">
<bean id="user" class="xyz.mxlei.pojo.User"/>
</beans>
在Java配置文件中载入xml配置文件
@Configuration
@ComponentScan(basePackages = "xyz.mxlei.server.*")
@ImportResource(value = {
"classpath:spring-other.xml"})
public class AppConfig{
}
1.8 使用Spring EL
- $表示读取上下文的属性值
- #表示启用Spring表达式
T表示使用引入的类
publiC class User{
@Value(${
admin.username})
String username;
@Value(#{
T{
System}.currentTimeMillis()})
Long createTime;
@Value(#{
3.14})
private float pi;
}
还没有评论,来说两句吧...