【Spring教程十】Spring框架实战:全面深入详解IOCDI之--纯注解开发模式下的依赖注入&&注解读取properties配置文件
作者:mmseoamin日期:2023-12-11

目录

  • 1 环境准备
  • 2 注解实现按照类型注入
  • 3 注解实现按照名称注入
  • 4 简单数据类型注入
  • 5 注解读取properties配置文件
  • 6 知识点总结

    欢迎大家回到《 Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《 如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《 全面深入详解IOC/DI注解开发》

    【Spring教程十】Spring框架实战:全面深入详解IOCDI之--纯注解开发模式下的依赖注入&&注解读取properties配置文件,在这里插入图片描述,第1张

    Spring为了使用注解简化开发,并没有提供构造函数注入、setter注入对应的注解,只提供了自动装配的注解实现。

    1 环境准备

    在学习之前,把案例环境介绍下:

    • 创建一个Maven项目
    • pom.xml添加Spring的依赖
      
      	
      		org.springframework
      		spring-context
      		5.2.10.RELEASE
      	
      
      
      • 添加一个配置类SpringConfig
        @Configuration
        @ComponentScan("com.itheima")
        public class SpringConfig {
        }
        
        • 添加BookDao、BookDaoImpl、BookService、BookServiceImpl类
          public interface BookDao {
          	public void save();
          }
          @Repository
          public class BookDaoImpl implements BookDao {
          	public void save() {
          		System.out.println("book dao save ..." );
          	}
          }
          public interface BookService {
          	public void save();
          }
          @Service
          public class BookServiceImpl implements BookService {
          	private BookDao bookDao;
          	public void setBookDao(BookDao bookDao) {
          		this.bookDao = bookDao;
          	}
          	public void save() {
          		System.out.println("book service save ...");
          		bookDao.save();
          	}
          }
          
          • 创建运行类App
            public class App {
            	public static void main(String[] args) {
            	AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
            		BookService bookService = ctx.getBean(BookService.class);
            		bookService.save();
            	}
            }
            

            最终创建好的项目结构如下:

            【Spring教程十】Spring框架实战:全面深入详解IOCDI之--纯注解开发模式下的依赖注入&&注解读取properties配置文件,在这里插入图片描述,第2张

            环境准备好后,运行后会发现有问题:

            【Spring教程十】Spring框架实战:全面深入详解IOCDI之--纯注解开发模式下的依赖注入&&注解读取properties配置文件,在这里插入图片描述,第3张

            出现问题的原因是,在BookServiceImpl类中添加了BookDao的属性,并提供了setter方法,但是目前是没有提供配置注入BookDao的,所以bookDao对象为Null,调用其save方法就会报控指针异常。

            2 注解实现按照类型注入

            对于这个问题使用注解该如何解决?

            (1) 在BookServiceImpl类的bookDao属性上添加@Autowired注解

            @Service
            public class BookServiceImpl implements BookService {
            	@Autowired
            	private BookDao bookDao;
            	// public void setBookDao(BookDao bookDao) {
            	// this.bookDao = bookDao;
            	// }
            	public void save() {
            		System.out.println("book service save ...");
            		bookDao.save();
            	}
            }
            

            注意:

            • @Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是写在属性上并将setter方法删除掉
            • 为什么setter方法可以删除呢?
              • 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值
              • 普通反射只能获取public修饰的内容
              • 暴力反射除了获取public修饰的内容还可以获取private修改的内容
              • 所以此处无需提供setter方法

                (2)@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加

                BookDaoImpl2

                @Repository
                public class BookDaoImpl2 implements BookDao {
                	 public void save() {
                		System.out.println("book dao save ...2");
                	 }
                }
                

                这个时候再次运行App,就会报错

                【Spring教程十】Spring框架实战:全面深入详解IOCDI之--纯注解开发模式下的依赖注入&&注解读取properties配置文件,在这里插入图片描述,第4张

                此时,按照类型注入就无法区分到底注入哪个对象,解决方案:按照名称注入

                • 先给两个Dao类分别起个名称
                  @Repository("bookDao")
                  public class BookDaoImpl implements BookDao {
                  	public void save() {
                  		System.out.println("book dao save ..." );
                  	}
                  }
                  @Repository("bookDao2")
                  public class BookDaoImpl2 implements BookDao {
                  	public void save() {
                  		System.out.println("book dao save ...2" );
                  	}
                  }
                  
                  • 此时就可以注入成功,但是得思考以下几个问题:
                    • @Autowired是按照类型注入的,给BookDao的两个实现起了名称,它还是有两个bean对象,为什么不报错?
                    • @Autowired默认按照类型自动装配,如果IOC容器中同类的Bean找到多个,就按照变量名和Bean的名称匹配。因为变量名叫bookDao而容器中也有一个booDao,所以可以成功注入。
                    • 分析下面这种情况是否能完成注入呢?

                      【Spring教程十】Spring框架实战:全面深入详解IOCDI之--纯注解开发模式下的依赖注入&&注解读取properties配置文件,在这里插入图片描述,第5张

                    • 不行,因为按照类型会找到多个bean对象,此时会按照bookDao名称去找,因为IOC容器只有名称叫bookDao1和bookDao2 ,所以找不到,会报NoUniqueBeanDefinitionException

                      3 注解实现按照名称注入

                      当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候该如何解决,就需要使用到@Qualifier来指定注入哪个名称的bean对象。

                      @Service
                      public class BookServiceImpl implements BookService {
                      	@Autowired
                      	@Qualifier("bookDao1")
                      	private BookDao bookDao;
                      	public void save() {
                      		System.out.println("book service save ...");
                      		bookDao.save();
                      	}
                      }
                      

                      @Qualifier注解后的值就是需要注入的bean的名称。

                      注意:@Qualifier不能独立使用,必须和@Autowired一起使用

                      4 简单数据类型注入

                      引用类型看完,简单类型注入就比较容易懂了。简单类型注入的是基本数据类型或者字符串类型,下面在BookDaoImpl类中添加一个name属性,用其进行简单类型注入

                      @Repository("bookDao")
                      public class BookDaoImpl implements BookDao {
                      	private String name;
                      	public void save() {
                      		System.out.println("book dao save ..." + name);
                      	}
                      }
                      

                      数据类型换了,对应的注解也要跟着换,这次使用@Value注解,将值写入注解的参数中就行了

                      @Repository("bookDao")
                      public class BookDaoImpl implements BookDao {
                      	@Value("itheima")
                      	private String name;
                      	public void save() {
                      		System.out.println("book dao save ..." + name);
                      	}
                      }
                      

                      注意数据格式要匹配,如将"abc"注入给int值,这样程序就会报错。

                      介绍完后,会有一种感觉就是这个注解好像没什么用,跟直接赋值是一个效果,还没有直接赋值简单,所以这个注解存在的意义是什么?

                      5 注解读取properties配置文件

                      @Value一般会被用在从properties配置文件中读取内容进行使用,具体如何实现?

                      步骤1:resource下准备properties文件

                      jdbc.properties

                      name=itheima888
                      

                      步骤2: 使用注解加载properties配置文件

                      在配置类上添加@PropertySource注解

                      @Configuration
                      @ComponentScan("com.itheima")
                      @PropertySource("jdbc.properties")
                      public class SpringConfig {
                      }
                      

                      步骤3:使用@Value读取配置文件中的内容

                      @Repository("bookDao")
                      public class BookDaoImpl implements BookDao {
                      	@Value("${name}")
                      	private String name;
                      	public void save() {
                      		System.out.println("book dao save ..." + name);
                      	}
                      }
                      

                      步骤4:运行程序

                      运行App类,查看运行结果,说明配置文件中的内容已经被加载到

                      【Spring教程十】Spring框架实战:全面深入详解IOCDI之--纯注解开发模式下的依赖注入&&注解读取properties配置文件,在这里插入图片描述,第6张

                      注意: