欢迎大家回到《 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
