一 依赖注入
1.1 什么是依赖注入
1.2 @Bean注入
spring IOC容器提供了依赖注入功能,可以将一个组件依赖到的对象,在使用之前注入到合适位置
spring IOC解决依赖注入;在配置类congfig中为Bean组件初始化方法增加参数,spring IOC容器会在初始化时候自动根据类型注入Bean组件对象
案例:
1.创建Saw
package cn.tedu.demo;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
public class Saw implements Serializable {
private String name="开天斧";
@Override
public String toString() {
return name;
}
}
2.创建Worker
package cn.tedu.demo;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
public class Worker implements Serializable {
private String name="光头强";
public Saw saw;
public void work(){
System.out.println(name + "使用" + saw +"砍树");
}
}
3.创建配置文件
package cn.tedu.context;
import cn.tedu.demo.Saw;
import cn.tedu.demo.Worker;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Configuration
public class Config {
@Bean
public Saw saw(){
return new Saw();
}
@Bean
/**
* spring会自动根据变量类型匹配Bean组件的类型
* 如果匹配上,就将Bean组件注入到方法参数中*/
public Worker worker(Saw s){
Worker worker = new Worker();
worker.saw=s;
return worker;
}
}
4.测试案例
package cn.tedu.test;
import cn.tedu.context.Config;
import cn.tedu.demo.Worker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
public class TestCase {
AnnotationConfigApplicationContext ctx;
@Before
public void init(){
ctx=new AnnotationConfigApplicationContext(Config.class);
}
@After
public void destroy(){
ctx.close();
}
@Test
public void testWorker(){
Worker worker = ctx.getBean("worker", Worker.class);
worker.work();
}
}
运行结果:
光头强使用开天斧砍树
spring IOC组件注入时候组件自动匹配规则:
- 首先按照注入参数类型查找相应类型的Bean组件,如果没有直接报错误
- 如果在是spring容器中能够匹配上唯一类型的Bean组件,则进行注入成功
- 如果按照类型匹配到两个bean组件,则查找组件ID和变量名是否匹配,如果匹配则注入成功
- 如果组件类型和组件ID都不能很好匹配则报错
注入失败案例
package cn.tedu.context;
import cn.tedu.demo.Saw;
import cn.tedu.demo.Worker;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Configuration
public class Config {
@Bean
public Saw saw(){
return new Saw();
}
@Bean
public Saw saw2(){
return new Saw();
}
@Bean
/**
* spring会自动根据变量类型匹配Bean组件的类型
* 如果匹配上,就将Bean组件注入到方法参数中*/
public Worker worker(Saw s){
Worker worker = new Worker();
worker.saw=s;
return worker;
}
}
运行结果:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'worker' defined in cn.tedu.context.Config: Unsatisfied dependency expressed through method 'worker' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'cn.tedu.demo.Saw' available: expected single matching bean but found 2: saw,saw2
碰到这种问题,只需要将需要注入的类型名改为@Bean相同的类型名
1.3 @Autowired
spring提供的组件扫描功能,在扫描时候也可以完成依赖注入,这样可以减少编码提高编程效率
案例
创建电锯类Saw
package cn.tedu.demo;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Component
public class Saw implements Serializable {
private String name="开天斧";
@Override
public String toString() {
return name;
}
}
创建工人类Worker
package cn.tedu.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Component
public class Worker implements Serializable {
private String name="光头强";
@Autowired
public Saw saw;
public void work(){
System.out.println(name + "使用" + saw +"砍树");
}
}
创建配置类
package cn.tedu.context;
import cn.tedu.demo.Saw;
import cn.tedu.demo.Worker;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Configuration
@ComponentScan(basePackages = "cn.tedu.demo")
public class Config {
}
测试案例
package cn.tedu.test;
import cn.tedu.context.Config;
import cn.tedu.demo.Worker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
public class TestCase {
AnnotationConfigApplicationContext ctx;
@Before
public void init(){
ctx=new AnnotationConfigApplicationContext(Config.class);
}
@After
public void destroy(){
ctx.close();
}
@Test
public void testWorker(){
Worker worker = ctx.getBean("worker", Worker.class);
worker.work();
}
}
测试结果
光头强使用开天斧砍树
1.4 set方法注入
测试案例:
二 IOC/DI解耦
2.1 利用接口解耦
利用spring IOC容器提供的DI可以将工具对象注入给工人对象,继而解决之间的依赖关系,并且由于依赖于接口,所以利用spring IOC就可以控制组件的组合关系,实现松耦合
案例:利用spring实现解耦
声明工具接口
package cn.tedu.demo2;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
/**
* 抽象的工具类型
* */
public interface Tool {
}
声明工人类
package cn.tedu.demo2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Component
public class Worker implements Serializable {
private String name="光头强";
@Autowired
private Tool tool;
public void work(){
System.out.println(name + "使用" + tool +"砍树");
}
}
声明电锯类
package cn.tedu.demo2;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
public class Saw implements Tool{
private String name="小锯子";
@Override
public String toString() {
return name;
}
}
声明斧子类
package cn.tedu.demo2;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Component
public class Axe implements Serializable,Tool{
private String name="开天斧";
@Override
public String toString() {
return name;
}
}
配置类
package cn.tedu.context2;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Configuration
@ComponentScan(basePackages = "cn.tedu.demo2")
public class Config {
}
测试类
package cn.tedu.test;
import cn.tedu.context2.Config;
import cn.tedu.demo2.Worker;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
public class TestCase2 {
AnnotationConfigApplicationContext ctx;
@Before
public void init(){
ctx=new AnnotationConfigApplicationContext(Config.class);
}
@After
public void destroy(){
ctx.close();
}
@Test
public void testWorker(){
Worker worker = ctx.getBean("worker", Worker.class);
worker.work();
}
}
测试结果
光头强使用开天斧砍树
2.2 @Autowired注入规则
案例:将斧子类和电锯类都加上@Component注解
1.在斧子类上设置自定义BeanID
package cn.tedu.demo2;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Component("tool")
public class Axe implements Serializable,Tool{
private String name="开天斧";
@Override
public String toString() {
return name;
}
}
测试结果:
光头强使用开天斧砍树
2.重构Worker类,设定@Qualifier("saw")
package cn.tedu.demo2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Component
public class Worker implements Serializable {
private String name="光头强";
@Autowired
@Qualifier("saw")
private Tool tool;
public void work(){
System.out.println(name + "使用" + tool +"砍树");
}
}
测试结果:
光头强使用小锯子砍树
2.3 同时使用@Bean @Component
1.利用@Bean在配置类Config中声明组件
package cn.tedu.context2;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Configuration
@ComponentScan(basePackages = "cn.tedu.demo2")
public class Config {
@Bean
public Date date(){
return new Date();
}
}
2.利用@Component声明组件,注入Date类型组件
package cn.tedu.demo2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
@Component
public class Employee {
private String name="傻狍子";
@Autowired
private Date date;
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", date=" + date +
'}';
}
}
3.测试案例
@Test
public void testEmployee(){
Employee employee = ctx.getBean("employee", Employee.class);
System.out.println(employee);
}
测试结果:输出当前系统时间,表示Date注入成功
Employee{name='傻狍子', date=Sat Oct 30 21:32:46 CST 2021}
案例:@Component 声明的组件注入到@Bean声明的组件
1.声明Bean类型
package cn.tedu.demo2;
/**
* @Author Mr WeiLiang
* @Date 2021/8/5 0005 09:22
* @Version 1.0
*/
public class Dept {
private String name="小良哥";
private Employee manager;
public void setManager(Employee manager){
this.manager=manager;
}
@Override
public String toString() {
return "Dept{" +
"name='" + name + '\'' +
", manager=" + manager +
'}';
}
}
2.在配置类Config中利用@Bean声明Bean组件
@Bean
public Dept dept(Employee employee){
Dept dept = new Dept();
dept.setManager(employee);
return dept;
}
3.测试案例
@Test
public void testDept(){
Dept dept = ctx.getBean("dept", Dept.class);
System.out.println(dept);
}
测试结果
ept{name='小良哥', manager=Employee{name='傻狍子', date=Sat Oct 30 21:47:32 CST 2021}}
3 使用Properties文件
3.1 Druld 连接池
案例:
1. 导入连接池
2.配置Config.java
测试
测试结果
3.2 @PropertlesSource 和 Envlronment
案例:
3.3 @Value
利用@Value可以读取当前系统环境Environment中的信息,注入到变量中,这个方式更加灵活方便