基于注解的DI
[TOC]
通过spring的注解完成对java对象的创建,属性的赋值,代替xml文件
ioc能够实现业务和对象之间的解耦合,例如service和dao对象之间的解耦合
常用注解:
- @Component、创建对象
- @Respotory、创建dao对象,用来访问数据库
- @Service、创建Service对象,处理业务逻辑,可以有事务的功能
- @Controller、创建控制器对象,接收请求,显示处理结果
- @Value、简单类型的属性赋值
- @Autowired、spring框架中引用类型赋值的注解,支持byName、byType,默认byType
- @Resource、jdk中的注解,使用自动注入给引用数据类型赋值,支持byName、byType,默认byName
一、使用注解的步骤
- 加入maven的依赖 spring-context ,在你加入spring-context的同时, 间接加入spring-aop的依赖,使用注解必须使用spring-aop依赖
- 在类中加入spring的注解(多个不同功能的注解)
- 在spring的配置文件中,加入一个组件扫描器的标签,说明注解在你的项目中的位置
<context:component-scan base-package="包名"/>
- 使用注解创建对象, 创建容器ApplicationContext
首先还是创建一个新的项目,在pom.xml文件中加入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency>
二、@Component
首先创建学生类
package com.md.b1; import org.springframework.stereotype.Component; /** * @author MD * @create 2020-08-08 15:51 * @Component: 创建对象的, 等同于<bean>的功能 * 属性:value 就是对象的名称,也就是bean的id值, * value的值是唯一的,创建的对象在整个spring容器中就一个 * 位置:在类的上面 * * @Component(value = "myStudent")等同于 * <bean id="myStudent" class="com.bjpowernode.ba01.Student" /> */ //@Component(value = "myStudent") // 省略value,常用 @Component("myStudent") // 不指定对象的名称,由spring默认提供:为类名首字母小写(student) //@Component public class Student { private String name; private Integer age; public Student() { System.out.println("我是Student的无参构造方法"); } public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
然后在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"> <!--声明组件扫描器,组件就是java对象 base-package:指定注解在你项目中的包名 component-scan工作方式:spring会扫描遍历base-package指定的包, 找包中以及子包中的所有的类,并找到类中的注解, 按照注解的功能创建对象,或者给属性赋值 --> <context:component-scan base-package="com.md.b1"/> </beans>
测试:
package com.md; import com.md.b1.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @author MD * @create 2020-08-08 16:05 */ public class MyTest01 { @Test public void test01(){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 从容器中获取对象 Student student = (Student) ac.getBean("myStudent"); System.out.println(student); } }
注意一:指定多个包的三种方式
<!--第一种方式:使用多次组件扫描器,指定不同的包--> <context:component-scan base-package="com.md.b1"/> <context:component-scan base-package="com.md.b2"/> <!--第二种方式:使用分隔符(;或,)分隔多个包名--> <context:component-scan base-package="com.md.b1;com.md.b2" /> <!--第三种方式:指定父包--> <context:component-scan base-package="com.md" />
重点:
注意二:spring中和@Component功能一致,创建对象的注解还有
- @Repository(用在持久层类的上面) : 放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的
- @Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的
- @Controller(用在控制器的上面):放在控制器(处理器)类的上面,创建控制器对象的,控制器对象,能够接受用户提交的参数,显示请求的处理结果。
以上三个注解的使用语法和@Component一样的。 都能创建对象,但是这三个注解还有额外的功能
@Repository,@Service,@Controller是给项目的对象分层的
某个类使用上面的三个注解都不合适的时候使用@Component
问题:创建对象的注解有几个,为什么有多个?
三、@Value
简单类型属性注入,需要在属性上使用注解@Value,该注解的 value 属性用于指定要注入的值
使用该注解完成属性注入时,类中无需 setter。当然,若属性有 setter,则也可将其加到 setter 上
如下:
package com.md.b2; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * @author MD * @create 2020-08-08 15:51 */ @Component("myStudent") public class Student { /** * @Value: 简单类型的属性赋值 * 属性: value 是String类型的,表示简单类型的属性值 * 位置: 1.在属性定义的上面,无需set方法,推荐使用。 * 2.在set方法的上面 */ // @Value(value = "比比东") @Value("比比东") private String name; // @Value(value = "18") @Value("22") private Integer age; public Student() { System.out.println("我是Student的无参构造方法"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
然后在spring的配置文件中applicationContext.xml加入组件扫描器
<context:component-scan base-package="com.md.b2"/>
测试
@Test public void test01(){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 从容器中获取对象 Student student = (Student) ac.getBean("myStudent"); System.out.println(student); //我是Student的无参构造方法 //Student{name='比比东', age=22} }
四、@Autowired
byType自动注入
@Autowired:spring框架提供的注解,实现引用类型的赋值
需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式(byType)
package com.md.b3; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * @author MD * @create 2020-08-08 16:39 */ @Component("student") public class Student { @Value("比比东") private String name; @Value("20") private Integer age; /** * 引用数据类型 * @Autowired:spring框架提供的注解,实现引用类型的赋值 * spring中通过注解给引用数据类型赋值的原理是使用自动注入,支持byName,byType * 默认使用的byType默认注入 * * 使用:在属性定义的上面,无需set方法,推荐 * 在set方法的上面 */ // 使用注解在School类里定义对象名称,以及属性值 或 使用bean的方式创建对象以及通过set方法给属性赋值 @Autowired private School school; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
School类
package com.md.b3; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * @author MD * @create 2020-08-08 16:40 */ @Component("mySchool") public class School { @Value("交大") private String name; @Value("上海") private String address; @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } public void setName(String name) { this.name = name; } public void setAddress(String address) { this.address = address; } }
然后在spring的配置文件中applicationContext.xml加入组件扫描器
<context:component-scan base-package="com.md.b3"/>
测试和上面一样,就不写了,除了使用注解还可以使用xml的方式
这样就是可以的,
<bean id="school" class="com.md.b3.School"> <property name="name" value="上海交通大学"/> <property name="address" value="上海"/> </bean>
五、@Qualifier
byName自动注入
由于@Autowired 默认使用的是byType,为了使用byName方式,
需要在引用属性上联合使用注解@Autowired 与@Qualifier
@Qualifier 的 value 属性用于指定要匹配的 Bean 的 id 值,
使用byName方式 1. 属性的上面加入@Autowired注解 2. 属性的上面加@Qualifier(value="bean的id")注解,表示使用指定名称的bean完成赋值 也就是使用这个对象来完成赋值
School类
@Component("school") public class School { @Value("厦门大学") private String name; @Value("厦门") private String address; @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
Student类
@Component("student") public class Student { @Value("比比东") private String name; @Value("20") private Integer age; // 在School类里通过注解直接对象名为school @Autowired @Qualifier("school") private School school; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
属性:required ,是一个boolean类型的,默认true
- required=true:表示引用类型赋值失败,程序报错,并终止执行。推荐使用
- required=false:引用类型如果赋值失败, 程序正常执行,引用类型是null
例如:还是在上面的程序上
使用的是byName的方式,而此时失误bean的id写错了
- 若使用默认值,则结果或报错
- 若按照下面写的执行,则不会报错,但数据为空
@Component("student") public class Student { @Value("比比东") private String name; @Value("20") private Integer age; // 在School类里通过注解直接对象名为school @Autowired(required = false) @Qualifier("schoo") private School school; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
六、@Resource
spring提供了对jdk中@Resource注解的支持。
@Resource注解既可以按名称匹配Bean,也可以按类型匹配 Bean。 默认是按名称注入(byName)
使用该注解,要求 JDK 必须是 6 及以上版本,@Resource 可在属性上,也可在 set 方法上
还是School类中
@Component("school") public class School { @Value("浙江大学") private String name; @Value("浙江") private String address; @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
此时Student类
@Component("student") public class Student { @Value("比比东") private String name; @Value("20") private Integer age; /** * 引用类型 * @Resource: 来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类型赋值 * 使用的也是自动注入原理,支持byName, byType .默认是byName * 位置: 1.在属性定义的上面,无需set方法,推荐使用。 * 2.在set方法的上面 */ //默认是byName: 先使用byName自动注入,如果byName赋值失败,再使用byType //@Resource // 若只使用byName方式,需要增加一个属性 name,name的值就是bean的id(对象名称) @Resource(name = "school") private School school; @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
在spring的配置文件中applicationContext.xml加入组件扫描器
<context:component-scan base-package="com.md.b6"/>
测试:
@Test public void test01(){ ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 从容器中获取对象 Student student = (Student) ac.getBean("student"); System.out.println(student); // Student{name='比比东', age=20, school=School{name='浙江大学', address='浙江'}} }
七、XML和注解对比
注解优点是:方便、直观、高效(代码少,没有配置文件的书写那么复杂)
缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的
适合于不是经常修改的
XML 方式优点是:配置和代码是分离的、在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载
缺点:编写麻烦,效率低,大型项目过于复杂
- 基于注解的DI容器配置元数据
- Spring与IoC_基于注解的DI_域属性的注入_使用Spring注解
- spring基于注解的IOC和DI配置
- (3)Spring基于注解的IOC配置以及注解配置依赖注入 DI
- Spring与IoC_基于注解的DI_基本注解的使用
- Spring--IoC--基于注解的DI-组件扫描器的base-package
- Spring--IoC--基于注解的DI-XML的优先级高于注解
- Spring_Spring与IoC_基于注解的DI
- spring、IoC控制反转和DI依赖注入入门、基于XML的Bean装配、基于注解的Bean装配
- Spring--IoC--基于注解的DI-@Component相关注解
- 【JavaWeb-23】spring、IoC控制反转和DI依赖注入入门、基于XML的Bean装配、基于注解的Bean装配
- Spring框架第四篇之基于注解的DI注入
- Spring IoC和DI基于注解使用
- Spring--IoC--基于注解的DI-@Scope
- 基于注解的DI
- Spring_Spring与IoC_基于注解的DI
- 三大组件之Spring第二章 基于XML和注解的DI
- Spring--IoC--基于注解的DI-使用Spring的JUnit4测试
- Spring:基于注解的DI
- spring4——IOC之基于注解的依赖注入(DI )