文章目录:
1.1 使用多个 context:component-scan 指定不同的包路径
2.1 @Component、@Value(存在于Spring中,用于给简单类型的属性赋值)
2.2 @Autowired(存在于Spring中,用于给引用类型的属性赋值,byType)
2.3 @Autowired、@Qualifier(存在于Spring中,用于给引用类型的属性赋值,byName)
2.4 @Resource(存在于jdk中,用于给引用类型的属性赋值)
1.基于注解的DI概述
在这里我们主要介绍以下几种注解:👇👇👇
1. 创建对象的注解:@Component、@Repository、@Service、@Controller。(来自Spring框架)
2. 简单类型的对象属性赋值:@Value。(来自Spring框架)
3. 引用类型的对象属性赋值:@Autowired、@Qualifier。(来自Spring框架)
4. 引用类型的对象属性赋值:@Resource。(来自JDK)
对于 DI 使用注解,将不再需要在 Spring 配置文件中声明 bean 实例。Spring 中使用注解,需要在原有 Spring 运行环境基础上再做一些改变。需要在 Spring 配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。
在基于注解的DI中,我们的Spring配置文件中将不再需要<bean>标签,而是在其中添加
<context:component-scan base-package="XXX" /> 这句代码。
在指定的包中扫描注解一共有以下三种方式:👇👇👇
1.1 使用多个context:component-scan 指定不同的包路径
<!-- 声明组件扫描器:使用注解必须加上这个语句 component-scan: 组件扫描器,组件是Java对象 属性base-package: 表示项目中的包名 框架会扫描这个包和子包中的所有类,找到类中的所有注解, 遇到注解后,按照注解表示的功能,去创建对象、给属性赋值 --> <context:component-scan base-package="com.bjpowernode.ba01" /> <context:component-scan base-package="com.bjpowernode.ba02" />
<!-- 可以使用分隔符(;或者,)指定多个包 --> <context:component-scan base-package="com.bjpowernode.ba01;com.bjpowernode.ba02" /> <context:component-scan base-package="com.bjpowernode.ba01,com.bjpowernode.ba02" />
base-package的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以 base-package 可以指定一个父包就可以。 但不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。
<!-- 也可以指定父包 --> <context:component-scan base-package="com.bjpowernode" />
2.注解的使用
2.1 @Component、@Value(存在于Spring中,用于给简单类型的属性赋值)
@Component: 表示创建对象,对象放到容器中,作用是 <bean>
属性: value,表示对象名称,也就是 <bean> 标签中的 id 属性值
位置: 在类的上面,表示创建此类的对象和@Component功能相同的创建对象的注解:
1. @Repository : 放在dao接口的实现类上面,表示创建dao对象,能访问数据库
2. @Service : 放在业务层接口的实现类上面,表示创建业务层对象,具有事务的功能
3. @Controller : 放在控制器类的上面,表示创建控制器对象,能够接收请求,把请求的处理结果显示给用户
@Repository,@Service,@Controller 是对@Component注解的细化,标注不同层的对象。
简单类型的属性赋值:@Value
属性: value,表示属性值,可以省略
位置:1) 在属性定义的上面,无需set方法,推荐使用
2) 在set方法上面
<?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"> <context:component-scan base-package="com.bjpowernode.ba01" /> </beans>
package com.bjpowernode.ba01; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * @Component: 表示创建对象,对象放到容器中,作用是 <bean> * 属性: value,表示对象名称,也就是 <bean> 标签中的 id 属性值 * 位置: 在类的上面,表示创建此类的对象 * * @Component(value = "myStudent") 等同于 * @Component("myStudent") 等同于 * <bean id="myStudent" class="com.bjpowernode.ba01.Student" /> * * 如果写成 @Component,则会使用框架的默认对象名称(类名首字母小写student) */ @Component("myStudent") public class Student { /** * 简单类型的属性赋值:@Value * 属性: value,表示属性值,可以省略 * 位置:1)在属性定义的上面,无需set方法,推荐使用 * 2)在set方法上面 */ @Value("张三") private String name; @Value("20") private int age; public Student() { System.out.println("Student类的无参构造方法被执行了"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
package com.bjpowernode; import com.bjpowernode.ba01.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * */ public class MyTest { @Test public void test01() { String config="applicationContext.xml"; ApplicationContext ctx=new ClassPathXmlApplicationContext(config); Student student= (Student) ctx.getBean("myStudent"); System.out.println("student === " + student); } }
2.2 @Autowired(存在于Spring中,用于给引用类型的属性赋值,byType)
引用类型:@Autowired
spring框架提供的,给引用类型赋值的,使用自动注入原理。支持byName、byType,默认是byType
属性:required:boolean类型的属性,默认为true
true:spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。
false:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null。位置:1)在属性定义的上面,无需set方法,推荐使用
2)在set方法上面byType自动注入:👇👇👇
<?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"> <context:component-scan base-package="com.bjpowernode.ba02"/> </beans>
package com.bjpowernode.ba02; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * */ @Component("mySchool") public class School { @Value("北京大学") private String name; @Value("北京海淀区") private String address; @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
package com.bjpowernode.ba02; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component("myStudent") public class Student { @Value("张三") private String name; @Value("20") private int age; /** * 引用类型:@Autowired * spring框架提供的,给引用类型赋值的,使用自动注入原理 * 支持byName、byType,默认是byType * 属性:required:boolean类型的属性,默认为true * true:spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。 * false:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null。 * 位置:1)在属性定义的上面,无需set方法,推荐使用 * 2)在set方法上面 * byType自动注入 */ @Autowired(required = true) private School school; public Student() { System.out.println("Student类的无参构造方法被执行了"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
package com.bjpowernode; import com.bjpowernode.ba02.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * */ public class MyTest02 { @Test public void test01() { String config="applicationContext02.xml"; ApplicationContext ctx=new ClassPathXmlApplicationContext(config); Student student= (Student) ctx.getBean("myStudent"); System.out.println("student === " + student); } }
2.3 @Autowired、@Qualifier(存在于Spring中,用于给引用类型的属性赋值,byName)
引用类型:@Autowired
spring框架提供的,给引用类型赋值的,使用自动注入原理。支持byName、byType,默认是byType
属性:required:boolean类型的属性,默认为true
true:spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。
false:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null。位置:1) 在属性定义的上面,无需set方法,推荐使用
2) 在set方法上面byName自动注入:
1) @Autowired:给引用类型赋值
2) @Qualifier(value="bean的id"):从容器中找到指定名称的对象,把这个对象赋值给引用类型
<?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"> <context:component-scan base-package="com.bjpowernode.ba03"/> </beans>
package com.bjpowernode.ba03; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * */ @Component("mySchool") public class School { @Value("清华大学") private String name; @Value("北京海淀区") private String address; @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
package com.bjpowernode.ba03; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component("myStudent") public class Student { @Value("李四") private String name; @Value("25") private int age; /** * 引用类型:@Autowired * spring框架提供的,给引用类型赋值的,使用自动注入原理 * 支持byName、byType,默认是byType * 属性:required:boolean类型的属性,默认为true * true:spring在创建容器对象时,会检查引用类型是否赋值成功,如果赋值失败,终止程序运行并报错。 * false:如果引用类型赋值失败,程序正常执行不会报错,此时引用类型的值为null。 * 位置:1)在属性定义的上面,无需set方法,推荐使用 * 2)在set方法上面 * byName自动注入: * 1)@Autowired:给引用类型赋值 * 2)@Qualifier(value="bean的id"):从容器中找到指定名称的对象,把这个对象赋值给引用类型 */ @Autowired(required = true) @Qualifier(value = "mySchool") private School school; public Student() { System.out.println("Student类的无参构造方法被执行了"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
package com.bjpowernode; import com.bjpowernode.ba03.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * */ public class MyTest03 { @Test public void test01() { String config="applicationContext03.xml"; ApplicationContext ctx=new ClassPathXmlApplicationContext(config); Student student= (Student) ctx.getBean("myStudent"); System.out.println("student === " + student); } }
2.4 @Resource(存在于jdk中,用于给引用类型的属性赋值)
引用类型:@Resource,来自jdk中,给引用类型赋值,支持byName、byType,默认是byName。Spring框架支持这个注解。
位置:1) 在属性定义的上面,无需set方法,推荐使用
2) 在set方法上面@Resource:先使用byName赋值,如果赋值失败,再使用byType
@Resource(name="mySchool"):表示只使用byName如果使用jdk1.8,则带有@Resource注解;如果高于jdk1.8,则没有这个注解。如需使用,需要在pom.xml文件中加入依赖:👇👇👇
<dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency>
<?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"> <context:component-scan base-package="com.bjpowernode.ba04"/> </beans>
package com.bjpowernode.ba04; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * */ @Component("mySchool") public class School { @Value("北京大学") private String name; @Value("北京海淀区") private String address; @Override public String toString() { return "School{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
package com.bjpowernode.ba04; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.annotation.Resource; @Component("myStudent") public class Student { @Value("张起灵") private String name; @Value("18") private int age; /** * 引用类型:@Resource,来自jdk中,给引用类型赋值,支持byName、byType,默认是byName * 位置:1)在属性定义的上面,无需set方法,推荐使用 * 2)在set方法上面 * @Resource:先使用byName赋值,如果赋值失败,再使用byType * @Resource(name="mySchool"):表示只使用byName * 如果使用jdk1.8,则带有@Resource注解; * 如果高于jdk1.8,则没有这个注解。如需使用,需要在pom.xml文件中加入依赖 */ @Resource private School school; public Student() { System.out.println("Student类的无参构造方法被执行了"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", school=" + school + '}'; } }
package com.bjpowernode; import com.bjpowernode.ba04.Student; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * */ public class MyTest04 { @Test public void test01() { String config="applicationContext04.xml"; ApplicationContext ctx=new ClassPathXmlApplicationContext(config); Student student= (Student) ctx.getBean("myStudent"); System.out.println("student === " + student); } }
3.对比——基于XML的DI和基于注解的DI
优点:①配置和代码是相分离的。
② 在xml中做修改,无需编译代码,只需重启服务器即可将新的配置加载。
缺点:编写麻烦,效率低,如果面对大型项目就显得过于复杂。
优点:方便、直观、高效(代码少,没有配置文件的书写那么复杂) 。
缺点:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。
4.Spring IoC总结
IoC用来管理对象,把对象放在容器中,进而创建对象、给对象属性赋值、管理对象之间的依赖关系。
IoC通过管理对象实现解耦合。往往解决的是业务逻辑对象之间的耦合关系,也就是service和dao之间的解耦合。
适合交给Spring容器的对象:service对象、dao对象、工具类对象。
不适合交给Spring容器的对象:实体类,servlet、listener、filter等web中的对象(它们是由tomcat创建和管理的)。