前言
上文说道Spring IOC思想:
Spring的IOC容器通过读取spring配置文件,可以帮助我们创建各种各样的对象,以实现调用方和被调用方在编译阶段的解耦 ,这些由Spring IOC创建出来的对象统称为Bean;
当我们把通过spring配置文件把需要的bean放到spring的IOC容器之后,如果这些容器中对象需要调用容器中其他对象,应该如何操作呢?
这就需要spring的依赖注入技术,容器+依赖注入(Dependency injection)实现Spring IOC思想:
当1个bean对象的控制权由调用方转交给spring的IOC容器之后;
我们可以通过Spring的xml配置文件或者注解,完成当前bean对象的依赖注入,去调用其他bean对象;
一、Bean的作用域
在Spring中,bean支持多种作用域如下所示,我们可以通过配置文件和注解进行配置;
- singleton(默认) 单例模式:即对象创建1次,创建之后一直存在,除非Spring IOC容器关闭;
- prototype 多例模式:即每次获取bean的时候,IOC都给我们创建一个新对象
- request域中生效:Spring创建一个Bean的对象,将对象存入到request域中
- session域中生效:Spring创建一个Bean的对象,将对象存入到session域中
1.Bean单例模式配置
<bean scope="singleton" id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">
2.Bean多例模式配置
<bean scope="prototype" id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">
二、Bean的生命周期
生命周期指得是1个事物,从创建到销毁的过程;
在Spring中,bean的作用范围会影响到其生命周期,所以我们要分单例和多例对象来研究bean的生命周期
init-method:指定的方法在当前对象(bean)创建之后执行
destroy-method指定的方法在当前对象(bean)销毁之前执行
<bean init-method="UserDao" destroy-method="destory" id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl">
创建:在容器创建的时候
在bean标签中嵌套constructor-arg标签可以完成bean对象构造函数赋值;
1.1.在类中添加有参构造
public class UserDaoImpl implements UserDao { private String name; private Integer age; private Date brithday; //对象属性 //添加无参构造器 public UserDaoImpl() { } //添加全参构造器 public UserDaoImpl(String name, Integer age, Date brithday) { this.name = name; this.age = age; this.brithday = brithday; }
1.2.通过配置文件配置属性的值
<!--相当于创建了1个对象Date brithday=new Date(); --> <bean id="date" class="java.util.Date"></bean> <!-- constructor-arg:构造函数完成依赖注入 name="name":指定构造器中形参的名称 value="张根":指定给当前属性赋的值【简单类型:基本类型+基本类型包装类+String】 vref="张根":指定给当前属性赋的值【引用类型】 --> <bean id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl"> <constructor-arg name="name" value="张根"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> <constructor-arg name="brithday" ref="date"></constructor-arg> </bean>
1.3.测试
UserDaoImpl{name='张根', age=18, brithday=Wed May 18 21:08:06 CST 2022}
property
//在类中提供属性的set()方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBrithday() { return brithday; } public void setBrithday(Date brithday) { this.brithday = brithday; }
2.2.在配置文件中设置属性的值
<!--相当于创建了1个对象Date brithday=new Date(); --> <bean id="date" class="java.util.Date"></bean> <!-- property:set方法完成依赖注入 name="name":指定构造器中形参的名称 value="张根":指定给当前属性赋的值【简单类型:基本类型+基本类型包装类+String】 vref="张根":指定给当前属性赋的值【引用类型】 --> <bean id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl"> <property name="name" value="张根"></property> <property name="age" value="18"></property> <property name="brithday" ref="date"></property> </bean>
2.3.测试
UserDaoImpl{name='张根', age=18, brithday=Wed May 18 21:27:22 CST 2022}
3.
array、map标签,可以对
集合复杂属性
package com.zhanggen.dao.impl; import com.zhanggen.dao.UserDao; import java.util.*; public class UserDaoImpl implements UserDao { //简单类型属性 private String name; private Integer age; //对象属性 private Date brithday; //集合复杂属性 private Set<String> mySet; private List<String> myList; private String[] myArr; private Map<String, String> myMap; //在类中提供属性的set()方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBrithday() { return brithday; } public void setBrithday(Date brithday) { this.brithday = brithday; } public Set<String> getMySet() { return mySet; } public void setMySet(Set<String> mySet) { this.mySet = mySet; } public List<String> getMyList() { return myList; } public void setMyList(List<String> myList) { this.myList = myList; } public String[] getMyArr() { return myArr; } public void setMyArr(String[] myArr) { this.myArr = myArr; } public Map<String, String> getMyMap() { return myMap; } public void setMyMap(Map<String, String> myMap) { this.myMap = myMap; } public void save() { System.out.println("用户保存成功"); } @Override public String toString() { return "UserDaoImpl{" + "name='" + name + '\'' + ", age=" + age + ", brithday=" + brithday + ", mySet=" + mySet + ", myList=" + myList + ", myArr=" + Arrays.toString(myArr) + ", myMap=" + myMap + '}'; } }
3.2.
<bean id="UserDao" class="com.zhanggen.dao.impl.UserDaoImpl"> <property name="name" value="张根"></property> <property name="age" value="18"></property> <property name="brithday" ref="date"></property> <property name="myList"> <list> <value>林心如</value> <value>范冰冰</value> </list> </property> <property name="mySet"> <set> <value>CC</value> <value>DD</value> </set> </property> <property name="myArr"> <array> <value>奔驰</value> <value>宝马</value> </array> </property> <property name="myMap"> <map> <entry key="key1" value="18"></entry> <entry key="key2" value="19"></entry> </map> </property> </bean>
3.3.测试
UserDaoImpl{name='张根', age=18, brithday=Wed May 18 21:50:56 CST 2022, mySet=[CC, DD], myList=[林心如, 范冰冰], myArr=[奔驰, 宝马], myMap={key1=18, key2=19}}
我们现在的配置都集中配在了一个applicationContext.xml文件中,这样会使这个文件很难维护。
针对这个问题,Spring给我们提供了两种解决方案:
- 在创建springIOC容器的时,同时引入多个配置文件
- 在主配置文件中引入其他配置文件
注意:
- 同一个xml文件中不允许出现相同id的bean,如果出现会报错
- 多个xml文件如果出现相同id的bean,不会报错,但是后加载的会覆盖前加载,所以尽量保证bean的名称是唯一的
1.同时引入多个配置文件
在创建spring IOC容器时一次读取多个配置文件
//1.读取多个配置文件,初始化SpringIOC容器 ClassPathXmlApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml","dateBean.xml");
2.引入1个主配置文件
spring IOC使用1个主配置文件,在主配置文件中引入其他配置文件
<!--引入其他配置文件--> <import resource="dateBean.xml"></import>
五、Spring IOC实现service和dao层(配置文件版本)
通过配置文件配置spring的IOC容器,实现service层和dao层解耦;
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring</artifactId> <groupId>com.zhanggen</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>day02-01-jt</artifactId> <dependencies> <!--spring核心--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.6.RELEASE</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.15</version> </dependency> <!--jdbcTemplate依赖所在--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.6.RELEASE</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> </dependency> </dependencies> </project>
2.定义
package com.zhanggen.dao; import com.zhanggen.domain.Account; import java.util.List; public interface AccountDao { //保存 void save(Account account); //查询所有 List<Account> queryAll(); //查询1条记录(根据name) Account queryByName(String name); //修改(根据name修改余额balance) void update(Account account); //删除(根据主键删除) void delete(Integer aid); }
3.
package com.zhanggen.dao.impl; import com.zhanggen.dao.AccountDao; import com.zhanggen.domain.Account; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import java.util.List; public class AccountDaoImpl implements AccountDao { //Spring的思想:需要对象了不能自己new了,而是向Spring 要1个bean private JdbcTemplate jdbcTemplate;//=new JdbcTemplate(); //期望Spring依赖注入 public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } @Override public void save(Account account) { jdbcTemplate.update("insert into account values (null,?,?)", account.getName(), account.getBalance()); } @Override public List<Account> queryAll() { List<Account> accountList = jdbcTemplate.query("select * from account;", new BeanPropertyRowMapper<Account>(Account.class)); return accountList; } @Override public Account queryByName(String name) { Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), name); return account; } @Override public void update(Account account) { jdbcTemplate.update("update account set balanc=? where name=?", account.getBalance(), account.getName()); } @Override public void delete(Integer aid) { jdbcTemplate.update("delete from account where aid=?", aid); } }
package com.zhanggen.serive; import com.zhanggen.domain.Account; import java.util.List; public interface AccountService { //保存 void save(Account account); //查询所有 List<Account> queryAll(); //查询1条记录(根据name) Account queryByName(String name); //修改(根据name修改余额balance) void update(Account account); //删除(根据主键删除) void delete(Integer aid); }
5.
package com.zhanggen.serive.impl; import com.zhanggen.dao.AccountDao; import com.zhanggen.domain.Account; import com.zhanggen.serive.AccountService; import java.util.List; public class AccountServiceImpl implements AccountService { private AccountDao accountDao; //Spring注入 public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void save(Account account) { accountDao.save(account); } @Override public List<Account> queryAll() { List<Account> accountList = accountDao.queryAll(); return accountList; } @Override public Account queryByName(String name) { Account account = accountDao.queryByName(name); return account; } @Override public void update(Account account) { accountDao.update(account); } @Override public void delete(Integer aid) { accountDao.delete(aid); } }
放到spring的IOC容器中,由spring的IOC容器进行管理;
<?xml version="1.0" encoding="UTF-8"?> <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" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- druidDataSource对象放到容器 DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8"); druidDataSource.setUsername("zhanggen"); druidDataSource.setPassword("123.com"); --> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8"></property> <property name="username" value="zhanggen"></property> <property name="password" value="123.com"></property> </bean> <!-- jdbcTemplate对象放到容器 JdbcTemplate jdbcTemplate = new JdbcTemplate(druidDataSource); --> <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="druidDataSource"></constructor-arg> <!--<property name="dataSource" ref="druidDataSource"></property>--> </bean> <!--dao对象放入容器--> <bean id="accountDao" class="com.zhanggen.dao.impl.AccountDaoImpl"> <property name="jdbcTemplate" ref="JdbcTemplate"></property> </bean> <!-- servicl对象放到spring容器 AccountService accountService=new AccountServiceImpl(); accountService.setAccountDao(accountDao); --> <bean id="accountService" class="com.zhanggen.serive.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> </beans>
7.测试
创建spring的IOC容器,从spring的IOC容器中获取service层对象;
package com.zhanggen.test; import com.zhanggen.domain.Account; import com.zhanggen.serive.AccountService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class AccountServiceTest { @Test public void testQueryAll() { //1.初始化Spring的IOC容器 ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从Spring的IOC容器中获取AccountService的实现类对象 AccountService accountService = act.getBean(AccountService.class); List<Account> accountList = accountService.queryAll(); for (Account account : accountList) { System.out.println(account); } } }
五、常用注解
首先明确注解就是对原来XML配置的简化,2者实现的功能是一样的。
1.
1.1.@Component注解
用于实例化对象,相当于配置文件中的<bean id="" class=""/>
它支持一个属性value,相当于xml中bean的id,如果不写,默认值为类名的首字母小写
1.2.@Controller @Service @Repository
这3个注解的功能跟@Component类似,他们分别标注在不同的层上。
- @Controller 标注在表示层的类上
- @Service 标注在业务层的类上
- @Repository 标注在持久层的类上
推荐使用这三个,当一个类实在不好归属在这三个层上时,再使用@Component
2.bean的作用域
@Scope用于指定bean的作用范围(单例和多例),相当于配置文件中的<bean scope="">
@Repository @Scope("singleton") public class AccountDaoImpl implements AccountDao {
3.bean的生命周期注解
@PostConstruct:此注解标注的方法会在当前对象创建之后自动执行
@PreDestroy:此注解标注的方法会在当前对象销毁之前自动执行
相当于<bean init-method="init" destroy-method="destory" />
//标注在类上表示使用AccountDaoImpl实现类创建1个对象放入spring的IOC容器里面 //@Component("accountDao") //定义当前对象在spring的IOC容器中表示,相当于xml的id,如果不声明id默认为当前类名首字母变小写 @Repository @Scope("singleton") public class AccountDaoImpl implements AccountDao { public void save() { System.out.println("保存成功了....."); } @PostConstruct//此注解标注的方法会在当前对象创建之后自动执行 public void init() { System.out.println("对象创建完毕了....."); } @PreDestroy //此注解标注的方法会在当前对象销毁之前自动执行 public void destory() { System.out.println("对象即将销毁....."); } }
4.1. @Autowired
这个注解表示依赖注入,可以标注在属性上,也可以标注在方法上,当@Autowired标注在属性上的时候,属性对应的set方法可以省略不写
4.2. @Qualifier
跟@Autowired联合使用,代表在按照类型匹配的基础上,再按照名称匹配
4.3.自动注入依赖原理
@Autowired:Spring会在他的IOC容器中按照被标注属性的类型进行寻找,如果查找到了一个就进行注入,如果查找不到或者查找到多个就报错
@Qualifier: 跟@Autowired联合使用,代表在按照类型匹配的基础上,再按照名称匹配
5.注解总结
spring容器是IOC思想的载体和体现;
@Component、@Controller/@Service/@Repository是把当前对象放到spring容器中;
@Autowired、@Qualifier是指定当前bean对象,需要依赖哪些spring的容器中bean对象;
getBean():1个对象的所有属性赋值(注入)成功之后,再向spring的IOC容器要出这个对象,调用该对象的方法;
注解配置 | 说明 | |
---|---|---|
< bean id="" class="" > | @Component、@Controller/@Service/@Repository | bean的实例化 |
< property name="" ref=""> | @Autowired、@Qualifier | bean的对象属性注入 |
< property name="" value=""> | @Value | bean的简单属性注入 |
< bean scope=""> | @Scope | 控制bean的作用范围 |
< bean init-method="init" destroy-method="destory" /> | @PostConstruct、@PreDestroy |
6.常用注解实现service和dao层
我们自己写的类(service层和dao层实现类)使用注解配置, 第三方的类(JdbcTemplate和Druid类对象)继续使用xml配置,实现web应用的service和dao层;
6.1.spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!--注解扫描--> <context:component-scan base-package="com.zhanggen"></context:component-scan> <!-- druidDataSource对象放到容器 DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName("com.mysql.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8"); druidDataSource.setUsername("zhanggen"); druidDataSource.setPassword("123.com"); --> <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8"></property> <property name="username" value="zhanggen"></property> <property name="password" value="123.com"></property> </bean> <!-- jdbcTemplate对象放到容器 JdbcTemplate jdbcTemplate = new JdbcTemplate(druidDataSource); --> <bean id="JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg name="dataSource" ref="druidDataSource"></constructor-arg> <!--<property name="dataSource" ref="druidDataSource"></property>--> </bean> </beans>
6.2.dao层
package com.zhanggen.dao.impl; import com.zhanggen.dao.AccountDao; import com.zhanggen.domain.Account; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.List; @Repository public class AccountDaoImpl implements AccountDao { //Spring的思想:需要对象了不能自己new了,而是向Spring 要1个bean @Autowired private JdbcTemplate jdbcTemplate;//=new JdbcTemplate(); @Override public void save(Account account) { jdbcTemplate.update("insert into account values (null,?,?)", account.getName(), account.getBalance()); } @Override public List<Account> queryAll() { List<Account> accountList = jdbcTemplate.query("select * from account;", new BeanPropertyRowMapper<Account>(Account.class)); return accountList; } @Override public Account queryByName(String name) { Account account = jdbcTemplate.queryForObject("select * from account where name=?", new BeanPropertyRowMapper<Account>(Account.class), name); return account; } @Override public void update(Account account) { jdbcTemplate.update("update account set balanc=? where name=?", account.getBalance(), account.getName()); } @Override public void delete(Integer aid) { jdbcTemplate.update("delete from account where aid=?", aid); } }
6.3.service层
package com.zhanggen.serive.impl; import com.zhanggen.dao.AccountDao; import com.zhanggen.domain.Account; import com.zhanggen.serive.AccountService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; //把AccountServiceImpl对象放到spring的容器中 @Service public class AccountServiceImpl implements AccountService { //去spring的容器中自动寻找AccountDao类型的bean进行依赖注入 @Autowired private AccountDao accountDao; @Override public void save(Account account) { accountDao.save(account); } @Override public List<Account> queryAll() { List<Account> accountList = accountDao.queryAll(); return accountList; } @Override public Account queryByName(String name) { Account account = accountDao.queryByName(name); return account; } @Override public void update(Account account) { accountDao.update(account); } @Override public void delete(Integer aid) { accountDao.delete(aid); } }
6.4.测试
package com.zhanggen.test; import com.zhanggen.domain.Account; import com.zhanggen.serive.AccountService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.List; public class AccountServiceTest { @Test public void testQueryAll() { //1.初始化Spring的IOC容器 ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从Spring的IOC容器中获取AccountService的实现类对象 AccountService accountService = act.getBean(AccountService.class); List<Account> accountList = accountService.queryAll(); for (Account account : accountList) { System.out.println(account); } } }
六、纯注解
随着SpringBoot的兴起,纯注解方式也变得越来越重要;
纯注解就是将xml中的所有 配置项、自己写的类和第三方提供类,全部使用注解实现对象的实例化,并放到spring的容器中 。
1.创建注解配置类
将原来spring配置文件中配置全部转换成1个Java类,这个Java类叫spring 配置类;
xml中的bean标签,转换成方法;
xml中非bean标签(如ComponentScan注解扫描),转换成方法的注解;
package com.zhanggen.config; import com.alibaba.druid.pool.DruidAbstractDataSource; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; //把spring配置中的配置内容,全部转换到当前配置类 /* bean标签---->方法 非bean标签(例如ComponentScan注解扫描)---->方法的注解 */ @ComponentScan("com.zhanggen") //注解扫描 public class SpringConfig { /* 编写1个方法,在方法中去创建对应对象,并且通过@bean注解来标识该方法 @Bean注解仅仅可以够标注在方法上,作用是将标注方法的返回值放到spring的容器 如果当前方法需要参数,@Bean可以自动从spring的容器中根据该参数类型查询(dl)到该参数,自动完成依赖注入 @Bean("druidDataSource")此注解可以声明bean的id,默认为getDataSource */ @Bean("druidDataSource") public DataSource getDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8"); dataSource.setUsername("zhanggen"); dataSource.setPassword("123.com"); return dataSource; } //@Bean注解:自动从spring的容器中根据dataSource参数声明的DataSource类型,查询(dl)到dataSource参数,自动完成依赖注入 @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } }
2.
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://192.168.56.18:3306/dbForJava?characterEncoding=utf8 jdbc.username=zhanggen jdbc.password=123.com
--------------------------------------------------------------------------------------------------------------
@PropertySource("db.properties")//导入类路径下某一个配置文件
@Value():用于给对象中简单属性进行赋值
package com.zhanggen.config; import com.alibaba.druid.pool.DruidAbstractDataSource; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.PropertySource; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; //把spring配置中的配置内容,全部转换到当前配置类 /* bean标签---->方法 非bean标签(例如ComponentScan注解扫描)---->方法的注解 */ @ComponentScan("com.zhanggen") //注解扫描 @PropertySource("db.properties")//导入类路径下某一个配置文件 public class SpringConfig { /* 编写1个方法,在方法中去创建对应对象,并且通过@bean注解来标识该方法 @Bean注解仅仅可以够标注在方法上,作用是将标注方法的返回值放到spring的容器 如果当前方法需要参数,@Bean可以自动从spring的容器中根据该参数类型查询(dl)到该参数,自动完成依赖注入 @Bean("druidDataSource")此注解可以声明bean的id,默认为getDataSource */ // @Value():用于给对象中简单属性进行赋值 @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("druidDataSource") public DataSource getDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } //@Bean注解:自动从spring的容器中根据dataSource参数声明的DataSource类型,查询(dl)到dataSource参数,自动完成依赖注入 @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } }
package com.zhanggen.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; //导入类路径下某一个配置文件 @PropertySource("db.properties") public class DbConfig { // @Value():用于给对象中简单属性进行赋值 @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("druidDataSource") public DataSource getDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
------------------------------------------------------------------------------------------------------------
package com.zhanggen.config; import com.alibaba.druid.pool.DruidAbstractDataSource; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.PropertySource; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; //把spring配置中的配置内容,全部转换到当前配置类 /* bean标签---->方法 非bean标签(例如ComponentScan注解扫描)---->方法的注解 */ @ComponentScan("com.zhanggen") //注解扫描 public class SpringConfig { /* 编写1个方法,在方法中去创建对应对象,并且通过@bean注解来标识该方法 @Bean注解仅仅可以够标注在方法上,作用是将标注方法的返回值放到spring的容器 如果当前方法需要参数,@Bean可以自动从spring的容器中根据该参数类型查询(dl)到该参数,自动完成依赖注入 @Bean("druidDataSource")此注解可以声明bean的id,默认为getDataSource */ //@Bean注解:自动从spring的容器中根据dataSource参数声明的DataSource类型,查询(dl)到dataSource参数,自动完成依赖注入 @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } }
---------------------------------------------------------------------------------------------------
ApplicationContext act = new AnnotationConfigApplicationContext(SpringConfig.class, DbConfig.class);
@Import(DbConfig.class) //从1个配置类中导入另1个配置类;
package com.zhanggen.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; //导入类路径下某一个配置文件 @PropertySource("db.properties") public class DbConfig { // @Value():用于给对象中简单属性进行赋值 @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("druidDataSource") public DataSource getDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
------------------------------------------------------------------------------------------------------------------
package com.zhanggen.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Import; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; //把spring配置中的配置内容,全部转换到当前配置类 /* bean标签---->方法 非bean标签(例如ComponentScan注解扫描)---->方法的注解 */ @ComponentScan("com.zhanggen") //注解扫描 @Import(DbConfig.class) //从1个配置类中导入另1个配置类 public class SpringConfig { @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } }
使用@Configuration声明的类就是配置类,本质是1个@Component注解;
在spring容器初始化的时候, 该配置类会自动创建并进入spring容器,以供主配置类的对象进行调用;
package com.zhanggen.config; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import javax.sql.DataSource; //导入类路径下某一个配置文件 @PropertySource("db.properties") //@Configuration 声明的类就是配置类,在spring容器初始化的时候, 配置类会自动创建并进入容器 @Configuration public class DbConfig { // @Value():用于给对象中简单属性进行赋值 @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("druidDataSource") public DataSource getDataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(driver); dataSource.setUrl(url); dataSource.setUsername(username); dataSource.setPassword(password); return dataSource; } }
------------------------------------------------------------------------------------------------------------------
package com.zhanggen.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Import; import org.springframework.jdbc.core.JdbcTemplate; import javax.sql.DataSource; //把spring配置中的配置内容,全部转换到当前配置类 /* bean标签---->方法 非bean标签(例如ComponentScan注解扫描)---->方法的注解 */ @ComponentScan("com.zhanggen") //注解扫描 public class SpringConfig { @Bean public JdbcTemplate getJdbcTemplate(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } }
@ComponentScan
组件扫描注解。 相当于xml配置文件中的< context:component-scan base-package=""/>
@Bean
该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。
@PropertySource
用于引入其它的properties配置文件
@Import
在一个配置类中导入其它配置类的内容
@Configuration
被此注解标注的类,会被Spring认为是配置类。Spring在启动的时候会自动扫描并加载所有配置类,然后将配置类中bean放入容器。
6.Spring整合到Junit测试
ApplicationContext对象然后再去运行spring的容器;
Junit支持通过@runWith()注解的方式,快速运行spring容器对象,以供我们调用spring容器中对象的功能;
<!--spring单元测试--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.6.RELEASE</version> </dependency>
package com.zhanggen.test; import com.zhanggen.domain.Account; import com.zhanggen.service.AccountService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; //1.切换运行器:使用SpringJUnit4ClassRunner启动spring的容器 @RunWith(SpringJUnit4ClassRunner.class) //2.启动spring的容器时加载配置类 //@ContextConfiguration(classes = SpringConfig.class) ////2.启动spring的容器时加载配置文件 //@ContextConfiguration("classpath:applicationContext.xml") public class AccountServiceTest { @Autowired private AccountService accountService; @Test public void testQueryAll() { List<Account> accountList = accountService.queryAll(); for (Account account : accountList) { System.out.println(account); } } }
7.@PostConstruc和@PreDestroy注解
@PostConstruc注释的方法,在当前对象初始化完成之后执行;
@PreDestory注释的方法,在对象销毁之前执行;
@Autowired不能注释static修饰的变量,静态成员属于类的,当类加载器加载静态变量时,Spring上下文尚未加载所以类加载器不会在bean中正确注入静态类,并且会失败
执行顺序如下
Constructor(对象的构造方法) -----> @Autowired(依赖注入) --------> @PostConstruct(注释的方法)
参考