基于XML配置文件的DI请参考上文
https://blog.csdn.net/MinggeQingchun/article/details/122880488
二、基于注解的DI
DI依赖注入(Dependency Injection,简称DI) 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例
Spring 中使用注解,需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解
1、声明组件扫描器(component-scan),组件就是Java对象
base-package:指定注解在项目中的包名
2、component-scan工作原理:
spring会扫描遍历base-package指定的包, 扫描包和子包中的所有类,找到类中的注解,按照注解创建Java对象,或者给属性赋值
3、加入<context:component-scan>标签,配置文件发生变化
(1)加入了新的约束文件:spring-context.xsd
(2)给这个新的约束文件起个命名空间的名称
xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.x
4、指定多个包的3种方式
(1)使用多个 context:component-scan 指定不同的包路径
<context:component-scan base-package="com.mycompany.package1" />
<context:component-scan base-package="com.mycompany.package2" />
(2)指定 base-package 的值使用分隔符
分隔符可以使用逗号(,)分号(;)还可以使用空格,不建议使用空格
<context:component-scan base-package="com.mycompany.package1;com.mycompany.package2" />
(3)base-package 是指定到父包名
但不建议直接使用com,这样会扫描磁盘中所有文件夹,导致效率降低
<context:component-scan base-package="com.mycompany" />
spring配置文件 applicationContext.xml
<?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.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 声明组件扫描器(component-scan),组件就是Java对象
base-package:指定注解在项目中的包名
component-scan工作原理:spring会扫描遍历base-package指定的包,
扫描包和子包中的所有类,找到类中的注解,按照注解创建Java对象,或者给属性赋值
加入<context:component-scan>标签,配置文件发生变化
1、加入了新的约束文件:spring-context.xsd
2、给这个新的约束文件起个命名空间的名称
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"
-->
<!-- <context:component-scan base-package="com.mycompany.p1component" />-->
<context:component-scan base-package="com.mycompany.p2valuenormal" />
<!--加载属性配置文件-->
<context:property-placeholder location="classpath:objectvalue.properties" />
<!-- 指定多个包有3种方式
1、使用多次组件扫描器,指定不同的包
2、使用分隔符(; 或 ,),分隔多个包
3、指定父包(但不建议直接使用com,这样会扫描磁盘中所有文件夹,导致效率降低)
-->
<!-- <!– 1、使用多次组件扫描器,指定不同的包 –>-->
<!-- <context:component-scan base-package="com.mycompany.p1component" />-->
<!-- <context:component-scan base-package="com.mycompany.p2valuenormal" />-->
<!-- <!– 2、使用分隔符(; 或 ,),分隔多个包 –>-->
<!-- <context:component-scan base-package="com.mycompany.p1component;com.mycompany.p2valuenormal"-->
<!-- <!– 3、指定父包(但不建议直接使用com,这样会扫描磁盘中所有文件夹,导致效率降低) –>-->
<!-- <context:component-scan base-package="com.mycompany" />-->
</beans>
(一)@Component、@Repository、@Service、@Controller注解
1、@Component :创建对象,等同 <bean> 标签功能
(1)属性:value 对象的名称,就是 <bean>的 id 值 value值唯一,创建对象在整个spring容器中就仅有一个
(2)位置:类上面
(3)语法:
@Component(value = "myUser")
等同
<bean id="myUser" class="com.xx.User" />
spring中和@Component功能一致,创建对象的注解还有:
1、@Repository(持久层类的上面):放在dao的实现类上面, 表示创建dao对象,dao对象是能访问数据库的
2、@Service (业务层类的上面):放在service的实现类上面, 创建service对象,service对象是做业务处理,可以有事务等功能的
3、@Controller (控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的, 控制器对象,能够接受用户提交的参数,显示请求的处理结果
以上三个注解的使用语法和@Component一样的,都能创建对象,但是这三个注解还有额外的功能
@Repository ,@Service,@Controller是给项目的对象分层的
@Component有3中用法
(1)使用value属性,指定对象名称 @Component(value = "myUser")
(2)省略value关键字 @Component("myUser")
(3)不指定对象名称,由spring提供默认名称: 类名的首字母小写 @Component
/*
1、使用value属性,指定对象名称
@Component(value = "myUser")
2、省略value关键字
@Component("myUser")
3、不指定对象名称,由spring提供默认名称: 类名的首字母小写
@Component
*/
//使用value属性,指定对象名称
@Component(value = "myUser")
public class User {
}
测试代码
@Test
public void testComponent(){
String config = "applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
User user = (User) ac.getBean("myUser");
//不指定对象名称,由spring提供默认名称: 类名的首字母小写 @Component
// User user = (User) ac.getBean("user");
System.out.println(user);
}
(二)@Value简单类型赋值
@Value : 简单类型属性赋值
(1)属性: value
【1】String类型,表示简单类型属性值
【2】也可使用属性配置文件加载,@Value("${属性的key}")
在 applicationContext.xml 文件中加载属性配置文件
<!--加载属性配置文件-->
<context:property-placeholder location="classpath:objectvalue.properties" />
objectvalue.properties属性配置文件
myName=admin
myAge=18
使用
@Value("${myName}")//使用属性配置文件中的数据
private String userName;
// @Value("18")
@Value("${myAge}")//使用属性配置文件中的数据
private int age;
(2)位置: 1、在属性定义上面,无需set方法(建议使用);2、在set方法上面
//使用value属性,指定对象名称
@Component(value = "myUser")
public class User {
/**
* @Value : 简单类型属性赋值
* 属性: value String类型,表示简单类型属性值
* 也可使用属性配置文件加载,@Value("${属性的key}")
* 位置: 1、在属性定义上面,无需set方法(建议使用)
* 2、在set方法上面
*/
// @Value("admin")
@Value("${myName}")//使用属性配置文件中的数据
private String userName;
// @Value("18")
@Value("${myAge}")//使用属性配置文件中的数据
private int age;
public User() {
System.out.println("spring会调用User类的无参构造方法创建对象");
}
// @Value("admin")
public void setUserName(String userName) {
this.userName = userName;
}
// @Value("18")
public void setAge(int age) {
this.age = age;
}
}
(三)@Autowired
1、byType
@Autowired 默认使用的是 byType自动注入
位置: 1、在属性定义的上面,无需set方法(建议使用) 2、在set方法的上面
//使用value属性,指定对象名称
@Component(value = "myUser")
public class User {
/**
* 引用类型 @Autowired(byType)
* @Autowired :spring框架提供的注解,实现引用类型赋值
* spring通过注解给引用类型赋值,使用的是自动注入原理,支持 byName,byType
* @Autowired 默认使用的是 byType自动注入
*
* 位置:
* 1、在属性定义的上面,无需set方法(建议使用)
* 2、在set方法的上面
*/
@Autowired
private Address address;
}
@Component(value = "myAddress")
public class Address {
}
2、byName和@Qualifier
@Autowired使用byName方式
在属性上加入 @Autowired;在属性上还要加上@Qualifier(value = "bean的id"):表示使用指定名称的bean完成赋值
注:@Autowired 和 @Qualifier 注解没有先后顺序之分,一般先声明功能,将@Autowired写在上面
//使用value属性,指定对象名称
@Component(value = "myUser")
public class User {
@Value("admin")
// @Value("${myName}")//使用属性配置文件中的数据
private String userName;
@Value("18")
// @Value("${myAge}")//使用属性配置文件中的数据
private int age;
/**
* 引用类型 @Autowired(byType)
* @Autowired :spring框架提供的注解,实现引用类型赋值
* spring通过注解给引用类型赋值,使用的是自动注入原理,支持 byName,byType
* 1、@Autowired 默认使用的是 byType自动注入
* 位置:
* (1)在属性定义的上面,无需set方法(建议使用)
* (2)在set方法的上面
*
* 2、@Autowired使用byName方式
* 在属性上加入 @Autowired;
* 在属性上还要加上@Qualifier(value = "bean的id"):表示使用指定名称的bean完成赋值
* 注:
* @Autowired 和 @Qualifier 注解没有先后顺序之分,一般先声明功能,将@Autowired写在上面
*/
@Autowired
@Qualifier("myAddress")
private Address address;
}
@Component(value = "myAddress")
public class Address {
}
3、required属性
required 属性,是一个Boolean类型,默认 true
required = true :表示引用类型赋值失败,程序报错,并终止执行
required = false :表示引用类型赋值失败,程序正常执行,引用类型为 null
一般无特殊请款,建议使用required = true,将问题尽早暴露,防止后续出现空指针异常
required = true :如果spring找不到引用对象bean的id,程序报错如下
NoSuchBeanDefinitionException: No qualifying bean of type 'com.mycompany.p5referenceautowiredrequired.Address' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=myAddress-1)}
//使用value属性,指定对象名称
@Component(value = "myUser")
public class User {
/**
* 引用类型 @Autowired(byType)
* required 属性,是一个Boolean类型,默认 true
* required = true :表示引用类型赋值失败,程序报错,并终止执行
* required = false :表示引用类型赋值失败,程序正常执行,引用类型为 null
* 一般无特殊请款,建议使用required = true,将问题尽早暴露,防止后续出现空指针异常
*
* required = true :如果spring找不到引用对象bean的id,程序报错如下
NoSuchBeanDefinitionException: No qualifying bean of type 'com.mycompany.p5referenceautowiredrequired.Address' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=myAddress-1)}
*
*/
@Autowired(required = false)
@Qualifier("myAddress-1")
private Address address;
}
@Component(value = "myAddress")
public class Address {
}
(四)@Resource
@Resource :来自JDK中的注解(包名:javax.annotation.Resource),spring框架提供了对该注解的功能支持,可以使用它给引用类型赋值
@Resource 工作原理:使用自动注入,支持byName, byType
@Resource 注解若不带任何参数,默认是 按名称的方式注入 byName(先使用byName自动注入,如果byName赋值失败,再使用byType)
位置:1、在属性定义的上面,无需set方法(建议使用);2、在set方法上面
1、默认byName,失败则使用byType
//使用value属性,指定对象名称
@Component(value = "myUser")
public class User {
/**
* 引用类型 @Resource
* @Resource :来自JDK中的注解(包名:javax.annotation.Resource),spring框架提供了对该注解的功能支持,可以使用它给引用类型赋值
* @Resource 工作原理:使用自动注入,支持byName, byType
* @Resource 注解若不带任何参数,默认是 按名称的方式注入 byName(先使用byName自动注入,如果byName赋值失败,再使用byType)
* 位置:
* 1、在属性定义的上面,无需set方法(建议使用)
* 2、在set方法上面
*/
//默认是byName: 先使用byName自动注入,如果byName赋值失败,再使用byType
@Resource
private Address address;
}
2、使用byName
@Resource 只使用byName方式,需要增加一个属性 name;name的值为 bean 的 id名称
//使用value属性,指定对象名称
@Component(value = "myUser")
public class User {
/**
* 引用类型 @Resource
* @Resource 只使用byName方式,需要增加一个属性 name
* name的值为 bean 的 id名称
*/
//只使用byName
@Resource(name = "myAddress")
private Address address;
}
@Component(value = "myAddress")
public class Address {
}