1.组件添加
1.1.@Configuration
我们在这里准备了两个组件,宠物类和用户类,用户类包含用户姓名和年龄,宠物类包含宠物名
public class User {
public String name;
public int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
public class Pet {
public String name;
public Pet(){
}
public Pet(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
如果我们是用原生的spring,我们想要把它们添加到容器中,我们可以创建一个spring的配置文件,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user01" class="com.yujie.boot.bean.User">
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
</bean>
<bean id="cat" class="com.yujie.boot.bean.Pet">
<property name="name" value="Tomcat"></property>
</bean>
</beans>
而现在我们的springboot已经不需要写这些xml配置文件了,springboot怎么给容器中添加这些组件呢?
在springboot底层我们可以使用@Configuration注解
基本使用
config类
/*
1.配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的。
2.配置类本身也是组件
3.
该注解里面有boolean proxyBeanMethods() default true;
与springboot1的不同proxyBeanMethods属性默认为true
代表代理bean的方法
Full、Lite配置
Full模式:proxyBeanMethods如果是true, 无论调用了多少次,都是从容器中找组件。Full模式
Lite模式:将其调成false,配置类在容器中不会保存代理对象,在外面每一次调用一次,都会新创建对象
组件依赖。
比如我们在User类里面加入了Pet组件,此时应该把proxyBeanMethods设置为true,就是对的,说明user依赖
了pet组件
* */
@Configuration(proxyBeanMethods=true) //告诉springboot这是一个配置类,等同于以前的配置文件
public class MyConfig {
/*
给容器中添加组件,以方法名作为组件的id,返回类型就是组件类型。
返回的值,就是组件在容器中的实例
外部无论对这个配置类中的这个组件注册方法调用多少次,获取的都是之前注册容器中的单实例。
* */
@Bean
public User user01(){
return new User("zhangsan",18);
}
@Bean("tom") //注解中直接赋予名字,此时方法名就不作为组件的id
public Pet tomcatPet(){
return new Pet("tomcat");
}
}
主程序类
/*
* @SpringBootApplication该注解告诉这是一个springboot应用
* 主程序类。所有启动的入口
* 固定写法
* */
@SpringBootApplication(scanBasePackages="com.yujie")
public class MainApplication {
public static void main(String[] args) {
//1.返回我们的IOC容器
ConfigurableApplicationContext run=SpringApplication.run(MainApplication.class,args);
//2.查看容器里面的组件
String [] names=run.getBeanDefinitionNames();
// for(String name:names){
// System.out.println(name);
// }
//3.从容器中获取组件
Pet tom01=run.getBean("tom",Pet.class);
Pet tom02=run.getBean("tom",Pet.class);
System.out.println("组件"+(tom01==tom02));
//配置类本身也是一个组件,我们看能不能获取配置类
//这里本身就是代理对象
MyConfig bean=run.getBean(MyConfig.class);
System.out.println(bean);
//当使用proxyBeanMethods=true时,我们直接调用配置类中的方法
//也就是代理对象调用的方法
//springboot总会检查这个组件是否在容器中有,如果有就不会新创建,一句话就是保持组件单实例
//如果是false,此时就不再是代理对象,多次调用的时候输出就是false
User user=bean.user01();
User user1=bean.user01();
System.out.println(user=user1);
}
}
Full模式与Lite模式
示例
最佳实战
配置类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
再次总结一下轻量级模式和全模式模式:
调成false轻量级模式,springboot就不会去检查这个方法返回的东西在容器中有没有,即跳过检查,运行起来就会比较快。
调成true全模式,每一次外界对它的调用都会去容器中检查有没有。
推荐:如果只是给容器中注册组件,别人也不依赖我们的组件,我们一般都把它调成false,这样加载起来也比较快
如果我们组件在后面还要用,还要依赖,就设置为true,能保证依赖的组件就是容器中的依赖
1.2.@Bean、@Component、@Controller、@Service、@Repository
给容器中注册组件也可以使用以前的办法,比如上面,可以使用@Component代表是一个组件。@Controller、@Service、@Repository代表控制层、逻辑层、数据库层组件,默认只要这些组件写在包扫描的范围内。它们都是以前的用法
1.3.@ComponentScan、@Import
ComponentScan指定包扫描规则。
@Import可以给容器中导入组件。可以写在配置类或者组件里面。
@Import({User.class, DBHelper.class})给容器中自动创建出这两个类型的组件、默认组件的名字就是全类名
配置类
@Import({User.class, DBHelper.class})
@Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
public class MyConfig {
}
测试类
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
//...
//5、获取组件
String[] beanNamesForType = run.getBeanNamesForType(User.class);
for (String s : beanNamesForType) {
System.out.println(s);
}
DBHelper bean1 = run.getBean(DBHelper.class);
System.out.println(bean1);
1.4.@Conditional条件装配
条件装配:满足Conditional指定的条件,则进行组件注入
下图是它派生的各种注解
每一个注解都代表不同的功能,比如ConditionalOnBean:即当容器中存在我们指定的bean的时候,我们才干某些事情,ConditionalOnMissingBean,当容器中没有这些组件的时候,我们就干某些事情,ConditionOnclass,当容器中有某些类的时候,我们才干某种事情。ConditionalResource.当项目的类路径中存在指定的资源的时候,才干某些事情.ConditionalOnWebApplication.当我们是web应用的时候,我们才干某些事情,ConditionalOnSingleCandidate,指定组件只有一个实例,或者多个实例,但只有一个主实例,等等。
实例,当我们把MyConfig类中的tomcatPet方法上面的@Bean注解注释掉之后,
@Bean
public User user01(){
return new User("zhangsan",18);
}
//@Bean("tom") //注解中直接赋予名字,此时方法名就不作为组件的id
public Pet tomcatPet(){
return new Pet("tomcat");
}
主程序类中输出
boolean tom=run.containsBean("tom");
System.out.println("容器中Tom组件 :" +tom);
boolean user01=run.containsBean("user01");
System.out.println("容器中Tom组件 :" +user01);
注意,此时User类中包含组件Pet类
public class User {
public String name;
public int age;
public Pet pet;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", pet=" + pet +
'}';
}
}
由于我们用户依赖这个宠物,而我们容器中没有这个宠物,所以也希望容器中没有宠物的时候,也别注册用户了。所以我们可以使用@ConditionalOnBean注解,也就是在容器中有某个组件,我们就可以干嘛
@ConditionalOnBean(name=“tom”)表示当容器中有tom这个组件的时候,我们就给容器中注入user01
@ConditionalOnBean(name="tom")
@Bean
public User user01(){
return new User("zhangsan",18);
}
如果我们在类上写上
@ConditionalOnBean(name="tom")
public class MyConfig {
}
当容器中有tom组件的时候,下面一堆才生效,否则就都不生效。
条件注解写到方法上,只有当条件成立之后, 这个方法返回的组件才会被注册到类中。否则就不生效。写在类上也类似。
@ConditionalOnMissingBean(name=“tom”)表示当容器中没有tom组件,我们就创建。
2.原生配置文件引入
2.1.@ImportResource
假如我们此时也有配置文件beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user01" class="com.yujie.boot.bean.User">
<property name="name" value="haha"></property>
<property name="age" value="18"></property>
</bean>
<bean id="cat" class="com.yujie.boot.bean.Pet">
<property name="name" value="hehe"></property>
</bean>
</beans>
可以看到,配置文件并没有生效,
如果我们不想放弃这个配置文件怎么办
比如,公司使用bean.xml文件生成配置bean,然而你为了省事,想继续复用bean.xml,@ImportResource粉墨登场。
@ImportResource注解可以导入spring的配置文件,让其生效。
当我们加上了注解之后
@ImportResource(“classpath:beans.xml”)
public class MyConfig {
}
3.配置绑定
如何利用Java读取到properties文件中的内容,并且把它封装到Javabean中,以供随时使用
传统方法:
public class getProperties {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties pps = new Properties();
pps.load(new FileInputStream("a.properties"));
Enumeration enum1 = pps.propertyNames();//得到配置文件的名字
while(enum1.hasMoreElements()) {
String strKey = (String) enum1.nextElement();
String strValue = pps.getProperty(strKey);
System.out.println(strKey + "=" + strValue);
//封装到JavaBean。
}
}
}
3.1.@ConfigurationProperties + @Component
Spring Boot一种配置配置绑定:
@ConfigurationProperties + @Component
假设有配置文件application.properties
mycar.brand=BYD
mycar.price=100000
只有在容器中的组件,才会拥有springboot提供的强大功能
@Component
@ConfigurationProperties(prefix = "mycar")
public class Car {
private String brand;
private Integer price;
public String getBrand(){ return brand;}
public void setBrand(String brand){ this.brand=brand;}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"brand='" + brand + '\'' +
", price=" + price +
'}';
}
}
控制器
public class HelloController {
@Autowired
Car car;
@RequestMapping("/car")
public Car car(){
return car;
}
/*这里表示请求的路径是/hello*/
@RequestMapping("/hello")
public String handle01(){
return "hello,Spring Boot 2";
}
}
3.2.@EnableConfigurationProperties + @ConfigurationProperties
1.开启Car配置绑定功能
2.把这个Car这个组件自动注册到容器中
@EnableConfigurationProperties(Car.class)
public class MyConfig {
...
}
@ConfigurationProperties(prefix = "mycar")
public class Car {
...
}
要么加载到容器中,要么开启配置绑定功能。