实现步骤:
1.在resources下创建一个jdbc.properties(文件的名称可以任意)
2.将数据库连接四要素配置到配置文件中
3.在Spring的配置文件中加载properties文件
4.使用加载到的值实现属性注入
准备环境:

创建一个jdbc.properties文件,添加对应的属性键值对
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
jdbc.username=root
jdbc.password=123
username = zhangsan
context命名空间在applicationContext.xml中开context命名空间,通过${key}获取对应的值实现注入
<context:property-placeholder location="jdbc2.properties,jdbc.properties" system-properties-mode="NEVER"/>
<context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>
<bean id="bookDao" class="com.hnu.dao.impl.BookDaoImpl">
<property name="name" value="${username}"/>
bean>
说明:
*.properties代表所有以properties结尾的文件都会被加载,可以解决方式一的问题,但是不标准classpath:代表的是从根路径下开始查找,但是只能查询当前项目的根路径package com.hnu.dao;
public interface BookDao {
public void save();
}
package com.hnu.dao.impl;
import com.hnu.dao.BookDao;
public class BookDaoImpl implements BookDao {
private String name;
public void setName(String name) {
this.name = name;
}
public void save() {
System.out.println("book dao save ..." + name);
}
}
package com.hnu;
import com.hnu.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.sql.DataSource;
import java.util.Map;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//打印环境变量
//Map getenv = System.getenv();
//System.out.println(getenv);
}
}
运行结果:

这里所说的核心容器,大家可以把它简单的理解为ApplicationContext
环境准备:

<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.10.RELEASEversion>
dependency>
dependencies>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="com.hnu.dao.impl.BookDaoImpl"/>
beans>
package com.hnu.dao;
public interface BookDao {
public void save();
}
package com.hnu.dao.impl;
import com.hnu.dao.BookDao;
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("constructor");
}
public void save() {
System.out.println("book dao save ...");
}
}
package com.hnu;
import com.hnu.dao.BookDao;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
public class App {
public static void main(String[] args) {
//如果在xml配置文件中加上lazy-init="true就会延迟加载
//创建容器方式一:
//ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//创建容器方式二:类路径下的XML配置文件
// ApplicationContext ctx = new FileSystemXmlApplicationContext("E:\\Spring\\spring_10_container\\src\\main\\resources\\applicationContext.xml");
//获取bean方式一:类型转换
//BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//bookDao.save();
//方式二:类的字节码文件
// BookDao bookDao1 = ctx.getBean("bookDao", BookDao.class);
// bookDao1.save();
//方式三:按类型注入 必须要确保IOC容器中该类型对应的bean对象只能有一个 该类型只能有一个实现类
// BookDao bookDao2 = ctx.getBean(BookDao.class);
// bookDao2.save();
//使用BeanFactory来创建IOC容器 目前已经不再使用了
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
//在加载ioc容器时不会加载对象,延迟加载
// BookDao bookDao = beanFactory.getBean(BookDao.class);
// bookDao.save();
}
}
使用BeanFactory来创建ioc容器运行结果,发现没有运行无参构造也就说明没有加载对象:

使用ClassPathXmlApplicationContext来创建容器,发现运行了无参构造,说明不存在延迟加载



注解开发可以极大简化开发,不用我们配之前的那些复杂配置,像xml容器配置文件,注入的配置都可以就此不用,只需要注解就可以实现!怎么实现,一块来看看√
环境准备:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.hnu"/>
beans>
component-scan
base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。
package com.hnu.dao;
public interface BookDao {
public void save();
}
package com.hnu.dao.impl;
import com.hnu.dao.BookDao;
import org.springframework.stereotype.Component;
//注解写在哪个类上,注解就是那个类的全类名,相当于一个bean
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
XML与注解配置的对应关系:
注意:@Component注解不可以添加在接口上,因为接口是无法创建对象的。

package com.hnu;
import com.hnu.dao.BookDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//按类型自动注入
BookDao bookDao = ctx.getBean(BookDao.class);
bookDao.save();
}
}
结果:

对于@Component注解,还衍生出了其他三个注解@Controller、@Service、@Repository
通过查看源码会发现:

这三个注解和@Component注解的作用是一样的,为什么要衍生出这三个呢?
方便我们后期在编写类的时候能很好的区分出这个类是属于表现层、业务层还是数据层的类。
上面已经可以使用注解来配置bean,但是依然有用到配置文件,在配置文件中对包进行了扫描,Spring在3.0版已经支持纯注解开发
配置环境

<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.10.RELEASEversion>
dependency>
dependencies>
package com.hnu.service;
public interface BookService {
public void save();
}
package com.hnu.service;
import org.springframework.stereotype.Service;
@Service
public class BookServiceImpl implements BookService {
public void save() {
System.out.println("book service save ...");
}
}
1.在配置类上添加@Configuration注解,将其标识为一个配置类,替换applicationContext.xml
2.在配置类上添加包扫描注解@ComponentScan替换
package com.hnu.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
//用注解代替包扫描 @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
//@ComponentScan("com.hnu")
@ComponentScan({"com.hnu.service","com.hnu.dao"})
public class SpringConfig {
}

public class AppForAnnotation {
public static void main(String[] args) {
//加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookService bookService = ctx.getBean(BookService.class);
bookService.save();
结果:

的作用是指定扫描包路径,注解为@ComponentScan环境准备:

<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.10.RELEASEversion>
dependency>
dependencies>
package com.hnu.dao;
public interface BookDao {
public void save();
}
package com.hnu.dao.impl;
//注解写在哪个类上,注解就是那个类的全类名,相当于一个bean
@Repository
//@Scope("prototype")是否是单例化,默认单例
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//在构造方法之后执行,替换 init-method
@PostConstruct
public void init() {
System.out.println("init...");
}
@PreDestroy
//在销毁方法之前执行,替换 destroy-method
public void destroy() {
System.out.println("destroy...");
}
}
package com.hnu.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
//用注解代替包扫描 @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
//@ComponentScan("com.hnu")
@ComponentScan({"com.hnu.service","com.hnu.dao"})
public class SpringConfig {
}
package com.hnu;
public class AppForAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDao bookDao = ctx.getBean(BookDao.class);
System.out.println(bookDao);
ctx.registerShutdownHook();
}
}
运行结果:

注意:@PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包
<dependency>
<groupId>javax.annotationgroupId>
<artifactId>javax.annotation-apiartifactId>
<version>1.3.2version>
dependency>
找不到的原因是,从JDK9以后jdk中的javax.annotation包被移除了,这两个注解刚好就在这个包中。

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

<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>5.2.10.RELEASEversion>
dependency>
dependencies>
package com.hnu.config;
@Configuration
//用注解代替包扫描 @ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
//@ComponentScan("com.hnu")
@ComponentScan({"com.hnu.service","com.hnu.dao"})
//加载jdbc配置文件
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
}
package com.hnu.dao;
public interface BookDao {
public void save();
}
package com.hnu.dao.impl;
//注解写在哪个类上,注解就是那个类的全类名,相当于一个bean
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
//注解实现简单数据类型的注入!!
@Value("${name}")
private String name;
public void save() {
System.out.println("book dao save ..."+name);
}
}
package com.hnu.service;
public interface BookService {
public void save();
}
package com.hnu.service;
@Service
public class BookServiceImpl implements BookService {
//注解实现按照类型注入!!
@Autowired
private BookDao bookDao;
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
@Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是写在属性上并将setter方法删除掉
为什么setter方法可以删除呢?
@Autowired是按照类型注入,那么对应BookDao接口如果有多个实现类,比如添加BookDaoImpl2
@Repository
public class BookDaoImpl2 implements BookDao {
public void save() {
System.out.println("book dao save ...2");
}
}
这个时候再次运行App,就会报错

此时,按照类型注入就无法区分到底注入哪个对象,解决方案:按照名称注入
先给两个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而容器中也有一个bookDao,所以可以成功注入。
分析下面这种情况是否能完成注入呢?

不行,因为按照类型会找到多个bean对象,此时会按照bookDao名称去找,因为IOC容器只有名称叫bookDao1和bookDao2,所以找不到,会报NoUniqueBeanDefinitionException
当根据类型在容器中找到多个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一起使用
1.@Value一般会被用在从properties配置文件中读取内容进行使用
2.如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个
@PropertySource({"jdbc.properties","xxx.properties"})
3.@PropertySource注解属性中不支持使用通配符*,运行会报错
@PropertySource({"*.properties"})
4.@PropertySource注解属性中可以把classpath:加上,代表从当前项目的根路径找文件
@PropertySource({"classpath:jdbc.properties"})

package com.hnu;
public class AppForAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookService bookService = ctx.getBean(BookService.class);
bookService.save();
}
}
运行结果:
