IoC(Inversion of Control),IoC是一种通过描述来生成或获取对象的技术。
每一个需要管理的对象称为Spring Bean,而Spring管理这些Bean的容器称为Spring IoC容器
Spring Boot是基于注解的开发,在Spring Boot中通过注解来装配Bean到Spring IoC容器。
注释说明
- @Configuration:代表这是一个Java的配置文件,Spring的容器会根据它来生成IoC容器去装配Bean
- @Bean:代表将方法返回的POJO装配到IoC容器中,属性name定义这个Bean的名称,如果没有配置则将方法名称作为Bean的名称保存到IoC容器
- @Value: 指定具体的值,使得Spring IoC给对应的属性注入对应的值
- @Component:标明该类会被Spring IoC容器扫描装配,指定的名称是该Bean 的名称,如果不指定该类第一个字母小写作为该Bean的名称
- @ComponentScan:如果不指定包名,则只会扫描@Configuration所在的包下的Bean。如果指定报名,则扫描指定包名下的所有Bean。(具体请看接下来实例中AppConfig的注释)
- @Autowired:自动注入。根据属性的类型找到对应的Bean进行注入。如果对应类型的Bean不是唯一的会根据属性名称和Bean的名称进行匹配。设置@Autowired的属性required为false时如果找不到匹配的Bean,允许设置为null而不抛出异常
实例1
在com.springboot.test.bean包下有两个类,BookInfo和User
在com.springboot.test.config包下是AppConfig
AppConfig.java
@Configuration
@ComponentScan("com.springboot.test.bean")
public class AppConfig {
@Bean(name="defaultBook")
public BookInfo initDefBook() {
BookInfo bk = new BookInfo();
bk.setID("bk323411");
bk.setName("Crazy Spring Boot");
bk.setAuthor("Crazy Max");
return bk;
}
}
@Configuration注释标明这是一个配置文件,Spring根据它来扫描装配Bean
@ComponentScan注释指定了扫描"com.springboot.test.bean"包下的Bean
@Bean注释标明将initDefBook方法返回的BookInfo装配到Ioc容器,Bean的名称为defaultBook
BookInfo.java
package com.springboot.test.bean;
public class BookInfo {
private String id;
private String name;
private String author;
public void setID(String id) {
this.id = id;
}
public String getID() {
return id;
}
public void setName(String bkName) {
this.name = bkName;
}
public String getName() {
return name;
}
public void setAuthor(String bkAuthor) {
this.author = bkAuthor;
}
public String getAuthor() {
return author;
}
}
BookInfo就是一个POJO(Plain Ordinary Java Object)
User.java
package com.springboot.test.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component("user")
public class User {
@Value("1")
private Long id;
@Value("user_name_1")
private String name;
@Value("note_1")
private String note;
public Long getId() {
return id;
}
}
User中使用了@Component("user")注释,标明这是一个Bean名称是user。在Spring IoC容器进行扫描装配时会装配该Bean。
@Value在Spring IoC容器装配Bean时对属性设定值
BookInfo和User都作为Bean被扫描装配。两个的方式是有区别的,BookInfo通过在方法initBookInfo前加注释@Bean对BookInfo Bean进行装配
User通过在类定义前加@Bean来说明自己是一个Bean
main方法内容
@SpringBootApplication
public class SpringIoCTestApplication {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
User user = ctx.getBean(User.class);
System.out.println(user.getId()+"");
System.out.println("-----------DefaultBook------------------");
BookInfo book = ctx.getBean(BookInfo.class);
System.out.println(book.getID());
System.out.println(book.getName());
System.out.println(book.getAuthor());
SpringApplication.run(SpringIoCTestApplication.class, args);
}
}
加载配置
属性文件中可以定义一些我们实际项目使用中的配置信息如url,用户名,密码等。默认的属性文件application.properties可以添加这些信息。同时也可以生成各自的properties文件加载其中信息。
现在application.properties文件中添加如下信息
redis.url=192.168.22.11
redis.username=root
redis.password=redis123
database.driverName=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/dbtest
database.username=root
database.password=123456
取得指定的属性值
RedisConfig.java
@Component
public class RedisConfig {
@Value("${redis.url")
private String url = null;
@Value("${redis.username}")
private String username = null;
@Value("${redis.password}")
private String password = null;
private long expiredMinutes = 0;
public void setUrl(String url) {
System.out.println("Redis.url:" + url);
this.url = url;
}
public void setUsername(String username) {
System.out.println("Redis.username:" + username);
this.username = username;
}
public void setPassword(String password) {
System.out.println("Redis.password:" + password);
this.password = password;
}
}
在其中通过@Value取得application.properties中的值设定到相应的属性和方法中
RedisConfig是一个Bean所以添加@Component注释
同时在之前的AppConfig中@ComponentScan需要添加RedisConfig所在的包名。RedisConfig放在包com.springboot.test.config.bean下,所以在@ComponentScan中添加“com.springboot.test.config.bean”
@ComponentScan("com.springboot.test.bean,com.springboot.test.config.bean")
取得属性名称组下的所有值
通过使用注释@ConfigurationProperties可以取得属性名称组下的所有值driverName,url,username,password都会自动匹配DatabaseConfig中对应的属性设定
DatabaseConfig.java
@Component
@ConfigurationProperties("database")
public class DatabaseConfig {
private String driverName = null;
private String url = null;
private String username = null;
private String password = null;
public void setDriverName(String driverName) {
System.out.println("database.driverName:" + driverName);
this.driverName = driverName;
}
public void setUrl(String url) {
System.out.println("database.url:" + url);
this.url = url;
}
public void setUsername(String username) {
System.out.println("database.username:" + username);
this.username = username;
}
public void setPassword(String password) {
System.out.println("database.password:" + password);
this.password = password;
}
}
注释@ConfigurationProperties("database")指定了database属性组,所以在application.properties中database下的所有配置
如果需要添加新的properties文件,加载其中设定按照如下方法来做
加载指定的属性文件配置
在工程的resources下新建一个config目录,新建一个文件mongo.properties文件
mongo.properties
mongo.url=192.168.112.23
mongo.username=developer
mongo.password=mongo123
MongoConfig.java
@Component
@PropertySource(name="mongo.properties", value= {"classpath:config/mongo.properties"}, ignoreResourceNotFound=false, encoding="UTF-8")
public class MongoConfig {
@Value("${mongo.url}")
private String url;
@Value("${mongo.username}")
private String username;
@Value("${mongo.password}")
private String password;
public String showAllConfig() {
String allConfig = "mongo.url:" + url + "," + "mongo.username:"+username+"," + "mongo.password:" + password + ",";
return allConfig;
}
}
在main中加入
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
User user = ctx.getBean(User.class);
System.out.println(user.getId()+"");
System.out.println("-----------MongoDB configuration----------------");
MongoConfig mgCfg = ctx.getBean(MongoConfig.class);
System.out.println(mgCfg.getUrl());
System.out.println(mgCfg.getUsername());
System.out.println(mgCfg.getPassword());
SpringApplication.run(SpringIoCTestApplication.class, args);
}
条件装配
实际使用过程中某些情况下如果配置未设定如果仍然对Bean进行装配和初始化会导致异常。这是我们希望能够检测要配置选项如果需要选项都存在再进行装配和初始化。
使用@Conditional可以帮助完成该功能
@Bean(name="dataSource")
@Conditional(DatabaseConditional.class)
public Properties loadDataSource(
@Value("${database.driverName}") String driver,
@Value("${database.url") String url,
@Value("${database.username}") String username,
@Value("${database.password}") String password
) {
Properties props = new Properties();
props.setProperty("driverName", driver);
props.setProperty("usrl", url);
props.setProperty("username", username);
props.setProperty("password", password);
return props;
}
@Conditional注明要DatabaseContitional来进行配置选项的判断
DatabaseConditional.java中对配置选项进行判断
public class DatabaseConditional implements Condition{
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO Auto-generated method stub
Environment env = context.getEnvironment();
boolean allRequirements = env.containsProperty("database.driverName")
&& env.containsProperty("database.url")
&& env.containsProperty("database.username")
&& env.containsProperty("database.password");
if(allRequirements) {
System.out.println("Meet all database requirements");
} else {
System.out.println("Not all database requirements been met");
}
return allRequirements;
}
}
DatabaseConditional实现matches方法
实例代码在SpringIoCTest