欢迎大家回到《 Java教程之Spring30天快速入门》,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《 如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》,本文的上一篇为《 全面深入详解IOC/DI注解开发》
Spring为了使用注解简化开发,并没有提供构造函数注入、setter注入对应的注解,只提供了自动装配的注解实现。
在学习之前,把案例环境介绍下:
org.springframework spring-context 5.2.10.RELEASE
@Configuration @ComponentScan("com.itheima") public class SpringConfig { }
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(); } }
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); BookService bookService = ctx.getBean(BookService.class); bookService.save(); } }
最终创建好的项目结构如下:
环境准备好后,运行后会发现有问题:
出现问题的原因是,在BookServiceImpl类中添加了BookDao的属性,并提供了setter方法,但是目前是没有提供配置注入BookDao的,所以bookDao对象为Null,调用其save方法就会报控指针异常。
对于这个问题使用注解该如何解决?
(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(); } }
注意:
(2)@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加
BookDaoImpl2
@Repository public class BookDaoImpl2 implements BookDao { public void save() { System.out.println("book dao save ...2"); } }
这个时候再次运行App,就会报错
此时,按照类型注入就无法区分到底注入哪个对象,解决方案:按照名称注入
@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" ); } }
当根据类型在容器中找到多个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一起使用
引用类型看完,简单类型注入就比较容易懂了。简单类型注入的是基本数据类型或者字符串类型,下面在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值,这样程序就会报错。
介绍完后,会有一种感觉就是这个注解好像没什么用,跟直接赋值是一个效果,还没有直接赋值简单,所以这个注解存在的意义是什么?
@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类,查看运行结果,说明配置文件中的内容已经被加载到
注意:
@PropertySource({"jdbc.properties","xxx.properties"})
@PropertySource({"*.properties"})
@PropertySource({"classpath:jdbc.properties"})
知识点1:@Autowired
知识点2:@Qualifier
知识点3:@Value
知识点4:@PropertySource