当前位置:   article > 正文

Spring IOC的组件注册、依赖注入的实现方式_spring ioc使用的注册订阅模式么

spring ioc使用的注册订阅模式么

IOC—Inversion of Control,控制反转,是一种设计思想它能指导程序员如何设计出松耦合、更优良的程序代码。

如果不用IOC,创建、销毁对象、对象之间的依赖关系,都需要程序员自己在代码里面体现,各种new。

而有了IOC容器后,代码里只需要定义对象的基本信息,并将它注册到IOC容器中,让IOC管理它的生命周期(创建和销毁)以及它们之间的依赖关系。

 

第一章:将组件(对象)添加到ioc容器的四种方式

        第一节:bean方式(注解和xml两种方式)

        第二节:bean工厂方式(静态工厂、实例化工厂两种)

        第三节:包扫描+@controller、@Service、@Repository@Component(注解和xml两种方式)

        第四节:@Import注解快速注册

        第五节(拓展):@Conditional 根据条件判断bean是否可以添加到容器中,Spring底层经常使用

        第六节(拓展):@profile 根据当前环境,动态的激活和切换一系列组件

第二章:自动装配实现方式(即DI 依赖注入实现属性赋值)

         第七节:@Autowired 自动装配

         第八节:JSR-250(java规范)的注解@Resource

         第九节:xml配置实现装配的多种方式

         第十节(拓展):自定义组件实现xxxAware接口,使用spring底层的一些组件(BeanFactory、ApplictionContext等)

       

          

 

Action one:创建maven项目,添加spring和junit依赖:

  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-context</artifactId>
  4. <version>4.3.12.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>junit</groupId>
  8. <artifactId>junit</artifactId>
  9. <version>4.12</version>
  10. <scope>test</scope>
  11. </dependency>

 

第一节:bean方式注册组件

>定义User对象

  1. public class User {
  2. public User() {
  3. super();
  4. }
  5. public User(String name, Integer age) {
  6. super();
  7. this.name = name;
  8. this.age = age;
  9. }
  10. private String name;
  11. private Integer age;
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public Integer getAge() {
  19. return age;
  20. }
  21. public void setAge(Integer age) {
  22. this.age = age;
  23. }
  24. }

>xml方式实现注册

  1. <bean id="user" class="com.mote.pojo.User">
  2. <property name="name" value="zhangsan"></property>
  3. <property name="age" value="22"></property>
  4. </bean>

>注解方式实现注册

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import com.mote.pojo.User;
  4. //@Configuration 标注这是一个注解配置类,该类就相当于spring的配置文件applictionContext.xml
  5. @Configuration
  6. public class MainConfig {
  7. /**
  8. * @Bean表示向IOC容器中注册bean,value指定bean名称,如果不指定,默认使用方法名
  9. */
  10. @Bean(value="user")
  11. public User user(){
  12. return new User("lisi",25);
  13. }
  14. }

>测试类

  1. import org.junit.Test;
  2. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. import com.mote.config.MainConfig;
  5. import com.mote.pojo.User;
  6. public class MainTest {
  7. @Test //注解测试
  8. public void testAnnotation(){
  9. //加载Spring注解配置类
  10. AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
  11. //从容器中获取bean
  12. User user = application.getBean(User.class);
  13. System.out.println(user);
  14. }
  15. @Test //xml测试
  16. public void testXml(){
  17. //加载Spring-xml配置文件
  18. ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
  19. //从容器中获取bean
  20. User user = application.getBean(User.class);
  21. System.out.println(user);
  22. }
  23. }

>打印结果:

 

第二节:bean工厂方式(静态工厂、实例化工厂两种)

1:静态工厂模式:工厂类本身不需要实例化, 通过工厂类直接调用其中的静态方法生成bean对象。

定义对象Car:

  1. public class Car {
  2. private String name;
  3. private double money;
  4. public Car() {
  5. super();
  6. }
  7. public Car(String name, double money) {
  8. super();
  9. this.name = name;
  10. this.money = money;
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public double getMoney() {
  19. return money;
  20. }
  21. public void setMoney(double money) {
  22. this.money = money;
  23. }
  24. @Override
  25. public String toString() {
  26. return "Car [name=" + name + ", money=" + money + "]";
  27. }
  28. }

定义生产Car的静态工厂:

  1. public class CarFactory {
  2. /**
  3. * 静态方法,返回Car实例
  4. * @return
  5. */
  6. public static Car getCar(){
  7. return new Car("宝马",10000000.00);
  8. }
  9. }

配置xml:

  1. <!-- 配置Car工厂,调用getCar(),返回Car实例 -->
  2. <bean id="car" class="com.mote.pojo.CarFactory" factory-method="getCar"></bean>

测试打印:

  1. public class MainTest {
  2. @Test //注解测试
  3. public void testAnnotation(){
  4. ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
  5. Car car = application.getBean(Car.class);
  6. //Car car1 = (Car) application.getBean("car");
  7. System.out.println(car);
  8. }
  9. }

 

2:实例工厂模式:因为getCar方法不是静态的,需要先实例化CarFactory工厂,在通过carFactory调用getCar生产bean对象

定义对象Car:(和静态工厂模式的测试一致)

定义Car的实例化工厂:

  1. public class CarFactory {
  2. public Car getCar(){
  3. return Car("宝马",10000000.00);
  4. }
  5. }

配置xml:

  1. <!-- 配置Car工厂-->
  2. <bean id="carFactory" class="com.mote.pojo.CarFactory"></bean>
  3. <!-- 调用carFactory的getCar,配置car的实例 -->
  4. <bean id="car" factory-bean="carFactory" factory-method="getCar"></bean>

测试打印:(和静态工厂模式的测试一致)

 

第三节:包扫描+@controller、@Service、@Repository@Component(注解和xml两种方式)

>定义UserController,UserService,UserDao,UserTest,分别加上述注解

>项目目录结构:

>xml方式实现包扫描注册

  1. <!-- 开启包扫描 ,指定的包以及子包下 只要标注了@Controller、@Service、@Repositoy、@Component
  2. 的类都会被添加到spring容器中-->
  3. <context:component-scan base-package="com.mote"/>

>注解方式实现包扫描注册

  1. @Configuration
  2. //@ComponentScan 开启包扫描,value指定包名
  3. @ComponentScan(value = "com.mote")
  4. public class MainConfig {
  5. }

>测试类

  1. import org.junit.Test;
  2. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;
  4. import com.mote.config.MainConfig;
  5. public class MainTest {
  6. @Test //注解测试
  7. public void testAnnotation(){
  8. //加载Spring注解配置类
  9. AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
  10. //获取注册到容器中的组件name集合,遍历打印
  11. String[] names = application.getBeanDefinitionNames();
  12. for (String name : names) {
  13. System.out.println(name);
  14. }
  15. }
  16. @Test //xml测试
  17. public void testXml(){
  18. //加载Spring-xml配置文件
  19. ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("beans.xml");
  20. String[] names = application.getBeanDefinitionNames();
  21. for (String name : names) {
  22. System.out.println(name);
  23. }
  24. }
  25. }

>打印结果

第四节:@Import注解快速注册

Import注解实现注册有三种实现方式

1:@Import(要添加的组件)

  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.context.annotation.Import;
  3. import com.mote.dao.UserDao;
  4. import com.mote.service.UserService;
  5. @Configuration
  6. //@Import 快速给容器中导入一个组件,默认id是全类名
  7. //@Import(UserController.class) //注册一个
  8. @Import({UserService.class,UserDao.class}) //注册多个
  9. public class MainConfig {
  10. }

2:实现ImportSelector接口,自定义返回要注册的组件

  1. import org.springframework.context.annotation.ImportSelector;
  2. import org.springframework.core.type.AnnotationMetadata;
  3. public class MyImport implements ImportSelector {
  4. public String[] selectImports(AnnotationMetadata importingClassMetadata) {
  5. return new String[] { "com.mote.controller.UserService","com.mote.dao.UserDao" };
  6. }
  7. }
  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.context.annotation.Import;
  3. @Configuration
  4. @Import(MyImport.class)
  5. public class MainConfig {
  6. }

3:实现ImportBeanDefinitionRegistrar接口,实现手动注册

  1. import org.springframework.beans.factory.config.BeanDefinition;
  2. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  3. import org.springframework.beans.factory.support.RootBeanDefinition;
  4. import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
  5. import org.springframework.core.type.AnnotationMetadata;
  6. import com.mote.dao.UserDao;
  7. public class MyImport implements ImportBeanDefinitionRegistrar {
  8. /**
  9. * AnnotationMetadata:当前类的注解信息
  10. * BeanDefinitionRegistry:BeanDefinition注册类
  11. */
  12. public void registerBeanDefinitions(
  13. AnnotationMetadata importingClassMetadata,
  14. BeanDefinitionRegistry registry) {
  15. //判断容器中是否注册userDao
  16. boolean flag = registry.containsBeanDefinition("userDao");
  17. //向容器中注册bean,并指定bean_name为userDao
  18. BeanDefinition beanDefinition = new RootBeanDefinition(UserDao.class);
  19. registry.registerBeanDefinition("userDao", beanDefinition );
  20. }
  21. }
  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.context.annotation.Import;
  3. @Configuration
  4. @Import(MyImport.class)
  5. public class MainConfig {
  6. }

>测试类

  1. import org.junit.Test;
  2. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  3. import com.mote.config.MainConfig;
  4. public class MainTest {
  5. @Test //注解测试
  6. public void testAnnotation(){
  7. //加载Spring注解配置类
  8. AnnotationConfigApplicationContext application = new AnnotationConfigApplicationContext(MainConfig.class);
  9. //获取注册到容器中的组件name集合,遍历打印
  10. String[] names = application.getBeanDefinitionNames();
  11. for (String name : names) {
  12. System.out.println(name);
  13. }
  14. }
  15. }

>打印结果

方式一:

方式二:

方式三:

 

第五节(拓展):@Conditional 根据条件判断bean是否可以添加到容器中,Spring底层经常使用

需求描述:如果当前系统是Windows,注册User(“bier”,30),反之不注册

1:实现Condition接口,书写判断逻辑

  1. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  2. import org.springframework.context.annotation.Condition;
  3. import org.springframework.context.annotation.ConditionContext;
  4. import org.springframework.core.env.Environment;
  5. import org.springframework.core.type.AnnotatedTypeMetadata;
  6. public class MyConditional implements Condition{
  7. /**
  8. * ConditionContext:判断条件使用的上下文
  9. * AnnotatedTypeMetadata:注释信息
  10. */
  11. public boolean matches(ConditionContext context,
  12. AnnotatedTypeMetadata metadata) {
  13. //获取当前运行环境信息
  14. Environment environment = context.getEnvironment();
  15. //获取当前系统类型,判断是否是Windows
  16. String type = environment.getProperty("os.name");
  17. return type.contains("Windows")?true:false;
  18. }
  19. }

2:使用@Conditional注解进行判断

  1. import com.mote.pojo.User;
  2. @Configuration
  3. public class MainConfig {
  4. @Bean
  5. @Conditional({MyConditional.class})
  6. public User bier(){
  7. return new User("bier",30);
  8. }
  9. }

小技巧:eclipse模拟linux环境

测试类中点击鼠标右键,Run AS  >   RunConfigurations

测试:

  1. public class MainTest {
  2. @Test //注解测试
  3. public void test(){
  4. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
  5. String[] names = context.getBeanDefinitionNames(); //打印spring容器注册的bean名称
  6. for (String name : names) {
  7. System.out.println(name);
  8. }
  9. }
  10. }

windows环境运行结果打印:

linux系统运行结果打印:

 

 第六节(拓展):@profile 根据当前环境,动态的激活和切换一系列组件

 案例功能描述:根据当前环境决定使用相应的数据库
 * 默认情况下:数据库A
 * 测试环境下:数据库B
 * 开发环境下:数据库C

导入maven:dhcp连接池和mysql驱动

  1. <dependency>
  2. <groupId>commons-dbcp</groupId>
  3. <artifactId>commons-dbcp</artifactId>
  4. <version>1.4</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>mysql</groupId>
  8. <artifactId>mysql-connector-java</artifactId>
  9. <version>6.0.6</version>
  10. </dependency>

案例代码:

  1. import org.apache.commons.dbcp.BasicDataSource;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.context.annotation.Profile;
  5. /**
  6. * @Profile:加了该环境标识的bean,只有这个环境被激活后后才能注册到容器
  7. */
  8. @Configuration
  9. public class MainConfig {
  10. @Bean
  11. @Profile("default") //不指定的情况下,默认使用的数据库
  12. public BasicDataSource dataSourceDefault() {
  13. BasicDataSource dataSource = new BasicDataSource();
  14. dataSource.setUrl("jdbc:mysql://localhost:3306/A");
  15. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  16. dataSource.setUsername("root");
  17. dataSource.setPassword("123456");
  18. return dataSource;
  19. }
  20. @Bean
  21. @Profile("test") //测试环境
  22. public BasicDataSource dataSourceTest() {
  23. BasicDataSource dataSource = new BasicDataSource();
  24. dataSource.setUrl("jdbc:mysql://localhost:3306/B");
  25. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  26. dataSource.setUsername("root");
  27. dataSource.setPassword("123456");
  28. return dataSource;
  29. }
  30. @Bean
  31. @Profile("devlop") //开发环境
  32. public BasicDataSource dataSourceDev() {
  33. BasicDataSource dataSource = new BasicDataSource();
  34. dataSource.setUrl("jdbc:mysql://localhost:3306/C");
  35. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  36. dataSource.setUsername("root");
  37. dataSource.setPassword("123456");
  38. return dataSource;
  39. }
  40. }

测试代码:

  1. public class MainTest {
  2. @Test //注解测试
  3. public void test(){
  4. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
  5. String[] names = context.getBeanDefinitionNames();
  6. for (String name : names) {
  7. System.out.println(name);
  8. }
  9. }
  10. }

测试一:不指定环境变量,直接运行,打印如下

测试二:指定环境为test,运行打印

打印结果:

  第七节:@Autowired 自动装配

                @Autowired使用前提,userService已经注册到spring容器中

@Autowired实现装配的三种操作方式

1)标注在属性上

  1. /**
  2. * @Autowired 首先根据UserService类型去容器寻找Bean,
  3. * 如果这个类型有多个Bean,比如userService/userService1
  4. * 那么@Autowired就会根据属性名称userService去匹配.
  5. *
  6. * 另外,可以使用注解@Qualifier配合@Autowired使用,用于指定容器中特定id的Bean
  7. */
  8. //@Qualifier("userService")
  9. @Autowired
  10. private UserService userService;

2)标注在set方法上

  1. private UserService userService;
  2. @Autowired
  3. public void setUserService(UserService userService) {
  4. this.userService = userService;
  5. }

3)标注在构造器上

  1. private UserService userService;
  2. /**
  3. * 如果该类只有这一个构造器,那么这个@Autowired注解可以省略不写
  4. * 因为spring容器生成的时候,就必须根据这个构造器去创建对象
  5. */
  6. @Autowired
  7. public UserController(UserService userService) {
  8. super();
  9. this.userService = userService;
  10. }

 第八节:JSR-250(java规范)的注解@Resource

                  @Resource使用前提,userService已经注册到spring容器中  

  1. /**
  2. * @Resource JSR-250注解,用来激活资源,通过name属性,指定容器中特定id的bean
  3. */
  4. @Resource(name="userService")
  5. private UserService userService;

第九节:xml配置实现装配的多种方式

                

1)set方法注入依赖

xml:

  1. <bean id="userService" class="com.mote.service.UserService"/>
  2. <bean class="com.mote.controller.UserController">
  3. <property name="userService" ref="userService"/>
  4. </bean>

代码:

  1. private UserService userService;
  2. public void setUserService(UserService userService) {
  3. this.userService = userService;
  4. }

2)构造器注入依赖

xml:

  1. <bean id="userService" class="com.mote.service.UserService"></bean>
  2. <bean class="com.mote.controller.UserController">
  3. <constructor-arg name="userService" ref="userService"></constructor-arg>
  4. </bean>

代码:

  1. private UserService userService;
  2. public UserController(UserService userService) {
  3. this.userService = userService;
  4. }

3)静态工厂注入依赖和实例化工厂注入依赖

这两种方式其实就是通过set方法注入依赖,只是向容器中添加bean的方式不同。

 

第十节(拓展):自定义组件实现xxxAware接口,使用spring底层的一些组件

  1. import org.springframework.beans.BeansException;
  2. import org.springframework.beans.factory.BeanFactory;
  3. import org.springframework.beans.factory.BeanFactoryAware;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.ApplicationContextAware;
  6. public class MyAware implements ApplicationContextAware,BeanFactoryAware {
  7. private ApplicationContext applicationContext; //设置成员变量
  8. private BeanFactory beanFactory; //设置成员变量
  9. public void setApplicationContext(ApplicationContext applicationContext)
  10. throws BeansException {
  11. this.applicationContext = applicationContext; //赋值
  12. }
  13. public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
  14. this.beanFactory = beanFactory; //赋值
  15. }
  16. public void test(){
  17. //使用 applicationContext、beanFactory
  18. }
  19. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/139156
推荐阅读
相关标签
  

闽ICP备14008679号