day02-容器功能

饭宝  论坛元老 | 2023-3-13 22:45:14 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1038|帖子 1038|积分 3114

容器功能

1.Spring注入组件的注解

Spring中的传统注解@Component、@Controller、@Service、@Repository,在SpringBoot中仍然有效。
2.@Configuration

@Configuration是 Spring 3.0 添加的一个注解,用来代替原先 Spring 中的 applicationContext.xml 容器配置文件,所有这个配置文件里面能做到的事情都可以通过这个注解所在类来进行注册。
在SpringBoot项目中,依然可以使用Spring的容器文件来注入bean/获取bean,但是不推荐使用
2.1应用实例

例子:使用SpringBoot的注解@Configuration添加/注入组件
(1)Monster.java
  1. package com.li.springboot.bean;
  2. /**
  3. * @author 李
  4. * @version 1.0
  5. */
  6. public class Monster {
  7.     private Integer id;
  8.     private String name;
  9.     private Integer age;
  10.     private String skill;
  11.    
  12.     //省略无参,全参构造器,getter,setter以及toString方法
  13. }
复制代码
(2)配置类:BeanConfig.java
  1. package com.li.springboot.config;
  2. import com.li.springboot.bean.Monster;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.context.annotation.Scope;
  6. /**
  7. * @author 李
  8. * @version 1.0
  9. *
  10. * 1.@Configuration注解标识这是一个配置类,等价于spring的容器配置文件
  11. * 2.这时我们可以通过@Bean注解注入Bean对象到容器中
  12. * 3.当一个类被@Configuration标识,这个类也会被注入到容器中,因此也能在容器中获取这个类对象
  13. */
  14. @Configuration
  15. public class BeanConfig {
  16.     /**
  17.      * 1.@Bean表示给容器添加了一个组件,即Monster的bean对象
  18.      * 2.name = "monster_n1" 在配置,注入Bean时指定的名字/id,如果没有设置,
  19.      *   就使用方法名 monster01() :作为Bean的名字/id
  20.      * 3.Monster :方法的返回类型就是注入的bean类型
  21.      * 4.new Monster(200,"牛魔王",500,"芭蕉扇") 就是注入到容器中的具体 bean信息
  22.      * 5.默认为单例对象,如果要做成多例的,需要添加注解@Scope("prototype")
  23.      */
  24.     @Bean(name = "monster_n1")
  25.     public Monster monster01() {
  26.         return new Monster(200, "牛魔王", 500, "芭蕉扇");
  27.     }
  28. }
复制代码
(3)MainApp.java
  1. package com.li.springboot;
  2. import com.li.springboot.bean.Monster;
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.context.ConfigurableApplicationContext;
  6. /**
  7. * @author 李
  8. * @version 1.0
  9. */
  10. @SpringBootApplication(scanBasePackages = {"com.li"})
  11. public class MainApp {
  12.     public static void main(String[] args) {
  13.         ConfigurableApplicationContext ioc =
  14.                 SpringApplication.run(MainApp.class, args);
  15.         Monster monster_n1 = ioc.getBean("monster_n1", Monster.class);
  16.         Monster monster_n2 = ioc.getBean("monster_n1", Monster.class);
  17.         System.out.println("monster_n1=" + monster_n1
  18.                 + ",n1.hashCode=" + monster_n1.hashCode());
  19.         System.out.println("monster_n2=" + monster_n2
  20.                 + ",n2.hashCode=" + monster_n2.hashCode());
  21.     }
  22. }
复制代码
测试结果:成功注入容器,并且默认为单例对象
  1. monster_n1=Monster{id=200, name='牛魔王', age=500, skill='芭蕉扇'},n1.hashCode=1532800776
  2. monster_n2=Monster{id=200, name='牛魔王', age=500, skill='芭蕉扇'},n2.hashCode=1532800776
复制代码
2.2注意事项和细节

(1)配置类本身也是组件,因此也可以在容器中获取,并且默认也是单例的
(2)SpringBoot2新增特性:proxyBeanMethods--代理 bean 的方法。

  • ProxyBeanMethods 可以指定 Full 模式和 Lite 模式

    • Full模式:(proxyBeanMethods = true),保证修修饰的配置类中,每个@Bean 方法被调用多少次返回的组件都是单实例的,是代理方式
    • Lite模式:(proxyBeanMethods = false),保证修饰的配置类中,每个@Bean方法被调用多少次返回的组件都是新创建的,多例对象,是非代理方式
    • 特别说明:proxyBeanMethods 在调用 @Bean 方法时才生效,因此需要先获取BeanConfig 组件,再调用方法。而不是直接通过SpringBoot 主程序得到的容器来获取bean,直接通过ioc.getBean() 获取 Bean, proxyBeanMethods 值并不会生效

  • 如何选择: 组件依赖必须使用 Full 模式(默认),如果不需要组件依赖使用 Lite 模式。
  • Lite 模 也称为轻量级模式,因为不检测依赖关系,运行速度快
(3)配置类可以有多个,就和Spring可以有多个容器配置文件一样
例子:测试proxyBeanMethods--代理 bean 的方法。
以2.1的代码为例,Monster.java不变
(1)修改配置类的注解为@Configuration(proxyBeanMethods = true),其他不变
(2)修改MainApp.java:
  1. package com.li.springboot;
  2. import ...
  3. /**
  4. * @author 李
  5. * @version 1.0
  6. */
  7. @SpringBootApplication(scanBasePackages = {"com.li"})
  8. public class MainApp {
  9.     public static void main(String[] args) {
  10.         //启动SpringBoot应用程序/项目
  11.         ConfigurableApplicationContext ioc =
  12.                 SpringApplication.run(MainApp.class, args);
  13.         //1.先得到BeanConfig组件
  14.         BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
  15.         //2.通过beanConfig对象调用方法才能生效!!
  16.         Monster monster_01 = beanConfig.monster01();
  17.         Monster monster_02 = beanConfig.monster01();
  18.         System.out.println("monster_01=" + monster_01
  19.                            + ",hashcode=" + monster_01.hashCode());
  20.         System.out.println("monster_02=" + monster_02
  21.                            + ",hashcode=" + monster_02.hashCode());
  22.     }
  23. }
复制代码
注意:proxyBeanMethods 在调用 @Bean 方法时才生效,因此需要先获取BeanConfig 组件,再调用方法。
测试结果:哈希值相同,说明获取的对象是同一个,为单例对象
  1. monster_01=Monster{id=200, name='牛魔王', age=500, skill='芭蕉扇'},hashcode=1075996552
  2. monster_02=Monster{id=200, name='牛魔王', age=500, skill='芭蕉扇'},hashcode=1075996552
复制代码
(3)将配置类的注解改为:@Configuration(proxyBeanMethods = false),然后重新测试
测试结果:每次返回的对象都是新的对象,即多例对象
  1. monster_01=Monster{id=200, name='牛魔王', age=500, skill='芭蕉扇'},hashcode=1164699452
  2. monster_02=Monster{id=200, name='牛魔王', age=500, skill='芭蕉扇'},hashcode=594916129
复制代码
3.@Import

@Import 是 Spring 3.0 添加的新注解,用来修饰 @Configuration 注解修饰的类,在 Spring Boot 里面应用很多,它可以将普通类导入到spring容器中做管理。
源码:
  1. package org.springframework.context.annotation;
  2. import ...
  3. @Target({ElementType.TYPE})
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Documented
  6. public @interface Import {
  7.     Class<?>[] value();
  8. }
复制代码
通过源码可以看到该注解可以指定class的数组,通过该数组注入指定类型的Bean
3.1应用实例

(1)创建两个Bean,Dog.java和Cat.java
  1. package com.li.springboot.bean;
  2. /**
  3. * @author 李
  4. * @version 1.0
  5. */
  6. public class Dog {
  7. }
复制代码
  1. package com.li.springboot.bean;
  2. /**
  3. * @author 李
  4. * @version 1.0
  5. */
  6. public class Cat {
  7. }
复制代码
(2)配置类BeanConfig.java
  1. package com.li.springboot.config;
  2. import com.li.springboot.bean.Cat;
  3. import com.li.springboot.bean.Dog;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.context.annotation.Import;
  6. /**
  7. * @author 李
  8. * @version 1.0
  9. * 通过@Import方式注入了组件,默认的组件名字/id为类型的全类名:
  10. *  com.li.springboot.bean.Dog 和 com.li.springboot.bean.Cat
  11. */
  12. @Import({Dog.class, Cat.class})
  13. @Configuration//标识这是一个配置类,等价于配置文件
  14. public class BeanConfig {
  15. }
复制代码
(3)MainApp.java
  1. package com.li.springboot;
  2. import ...
  3. /**
  4. * @author 李
  5. * @version 1.0
  6. */
  7. @SpringBootApplication(scanBasePackages = {"com.li"})
  8. public class MainApp {
  9.     public static void main(String[] args) {
  10.         //启动SpringBoot应用程序/项目
  11.         ConfigurableApplicationContext ioc =
  12.                 SpringApplication.run(MainApp.class, args);
  13.         //测试@Import
  14.         Dog dogBean = ioc.getBean(Dog.class);
  15.         Cat catBean = ioc.getBean(Cat.class);
  16.         System.out.println("dogBean=" + dogBean);
  17.         System.out.println("catBean=" + catBean);
  18.     }
  19. }
复制代码
测试结果:
  1. dogBean=com.li.springboot.bean.Dog@12477988
  2. catBean=com.li.springboot.bean.Cat@2caf6912
复制代码
4.@Conditional


  • 条件装配:满足 Conditional 指定的条件,才进行组件注入
  • 它可以修饰类,接口或者枚举类型,还可以修饰在方法上
  • @Conditional 是一个根注解,它的下面有很多扩展注解
@Conditional扩展注解作用@ConditionalOnJava当JVM版本为指定的版本范围时触发实例化@ConditionalOnBean当容器中至少存在一个指定name或class的Bean时,进行实例化@ConditionalOnMissingBean当容器中指定name或class的Bean都不存在时,进行实例化@ConditionalOnExpression基于SpEL表达式的条件判断,当为true的时候进行实例化@ConditionalOnClass当类路径下至少存在一个指定的class时,进行实例化@ConditionalOnMissingClass当容器中指定class都不存在时,进行实例化@ConditionalOnSingleCandidate当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化@ConditionalOnProperty当指定的属性有指定的值时进行实例化@ConditionalOnResource当类路径下有指定的资源时触发实例化@ConditionalOnWebApplication当项目是一个Web项目时进行实例化@ConditionalOnNotWebApplication当项目不是一个Web项目时进行实例化@ConditionalOnJndi在JNDI存在的条件下触发实例化4.1应用实例

演示在SpringBoot中通过@ConditionalOnBean来注入组件
(1)指定条件:当容器中有name="monster_nmw"组件时,才注入dog01,代码如下:
  1. package com.li.springboot.config;
  2. import ...
  3. /**
  4. * @author 李
  5. * @version 1.0
  6. */
  7. @Configuration
  8. public class BeanConfig {
  9.     @Bean
  10.     public Monster monster01() {
  11.         return new Monster(200, "牛魔王", 500, "芭蕉扇");
  12.     }
  13.    
  14.     /**
  15.      * 1.@ConditionalOnBean(name = "monster_nmw")
  16.      *  表示当容器中存在id为monster_nmw的Bean时(对类型不做约束),
  17.      *        dog01这个Dog Bean才能注入到容器中
  18.      * 2.如果不符合条件,则不能注入容器
  19.      */
  20.     @Bean
  21.     @ConditionalOnBean(name = "monster_nmw")
  22.     public Dog dog01() {
  23.         return new Dog();
  24.     }
  25. }
复制代码
(2)MainApp.java
  1. package com.li.springboot;
  2. import ...
  3. /**
  4. * @author 李
  5. * @version 1.0
  6. */
  7. @SpringBootApplication(scanBasePackages = {"com.li"})
  8. public class MainApp {
  9.     public static void main(String[] args) {
  10.         ConfigurableApplicationContext ioc =
  11.                 SpringApplication.run(MainApp.class, args);
  12.         //演示@ConditionalOnBean的使用
  13.         Dog dog01 = ioc.getBean("dog01", Dog.class);
  14.         System.out.println("dog01=" + dog01);
  15.     }
  16. }
复制代码
测试结果:运行出错,因为容器中没有名为monster_nmw的 Bean,因此不能注入Dog Bean,也就无法通过getBean获取到Dog Bean对象。
5.@ImportResource

作用:原生功能配置文件引入,可以直接导入Spring传统的beans.xml到配置类中,可以认为是SpringBoot对Spring的兼容。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表