【Spring】Spring中的Bean

您所在的位置:网站首页 bean的注解方式 【Spring】Spring中的Bean

【Spring】Spring中的Bean

2023-06-03 16:43| 来源: 网络整理| 查看: 265

Bean的装配方式

简单记录-Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)-Spring中的Bean

文章目录Bean的装配方式基于XML的装配基于注解(Annotation)的装配自动装配 IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

控制反转(IoC)是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

依赖注入

什么是Bean的装配?

​ Bean的装配方式是将Bean装配注入到Spring IoC容器中 ,Bean的装配可以理解为依赖关系注入,Bean的装配方式即Bean依赖注入的方式。Spring容器支持多种形式的Bean的装配方式,如基于XML的装配、基于注解(Annotation)的装配和自动装配(其中最常用的是基于注解的装配)。基于注解的装配方式尤其重要,它是当前的主流装配方式。

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

基于XML的装配

Spring提供了两种基于XML的装配方式:设值注入(Setter Injection)和构造注入(Constructor Injection)。下面就讲解下如何在XML配置文件中使用这两种注入方式来实现基于XML的装配。

在Spring实例化Bean的过程中,Spring首先会调用Bean的默认构造方法来实例化Bean对象,然后通过反射的方式调用setter方法来注入属性值。因此,设值注入要求一个Bean必须满足以下两点要求。

Bean类必须提供一个默认的无参构造方法。 Bean类必须为需要注入的属性提供对应的setter方法。

使用设值注入时,在Spring配置文件中,需要使用元素的子元素来为每个属性注入值;

而使用构造注入时,在配置文件里,需要使用元素的子元素来定义构造方法的参数,可以使用其value属性(或子元素)来设置该参数的值。

在这里插入图片描述

下面通过一个案例来演示基于XML方式的Bean的装配。

基于XML的装配,使用方式如下:

创建Java类,提供有参、无参构造以及属性setter方法;

(1)在chapter02模块的src/main/java目录下,创建一个com.awen.assemble包,在该包中创建User类,并在类中定义username、password和list集合三个属性及其对应的setter方法,如文件所示。文件 User.java

```java

package com.awen.assemble; import java.util.List; public class User { private String username; private Integer password; private List list; /** * 1.使用构造注入 * 1.1提供带所有参数的有参构造方法。 / public User(String username, Integer password, List list) { super(); this.username = username; this.password = password; this.list = list; } /* * 2.使用设值注入 * 2.1提供默认空参构造方法 ; * 2.2为所有属性提供setter方法。 */ public User() { super(); } public void setUsername(String username) { this.username = username; } public void setPassword(Integer password) { this.password = password; } public void setList(List list) { this.list = list; } @Override public String toString() { return “User [username=” + username + “, password=” + password + “, list=” + list + “]”; } }

```

在文件User.java中,由于要使用构造注入,所以需要其有参和无参的构造方法。同时,为了输出时能够看到结果,还重写了其属性的toString()方法。

(2)在src/main/resources目录下,创建Spring配置文件beans5.xm,创建配置文件beans5.xml,在配置文件中通过构造注入和设值注入的方式装配User类的实例,如文件所示。文件 beans5.xml

"constructorvalue1" "constructorvalue2" "setlistvalue1" "setlistvalue2"

在上述配置文件中,元素用于定义构造方法的参数,其属性index表示其索引(从0开始), value属性用于设置注入的值,其子元素来为User类中对应的list集合属性注入值。然后又使用了设值注入方式装配User类的实例,其中元素用于调用Bean实例中的setter方法完成属性赋值,从而完成依赖注入,而其子元素同样是为User类中对应的list集合属性注入值。

(3)在com.awen.assemble包中,创建测试类XmlBeanAssembleTest,在类中分别获取并输出配置文件中的user1和user2实例,如文件所示。文件 XmlBeanAssembleTest.java

package com.awen.assemble; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class XmlBeanAssembleTest { public static void main(String[] args) { // 加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans5.xml"); // 构造方式输出结果 System.out.println(applicationContext.getBean("user1")); // 设值方式输出结果 System.out.println(applicationContext.getBean("user2")); } }

执行程序后,控制台的输出结果如下所示,

D:\Environments\jdk-11.0.2\bin\java.exe -javaagent:D:\Java\ideaIU-2019.2.win\lib\idea_rt.jar=3035:D:\Java\ideaIU-2019.2.win\bin -Dfile.encoding=UTF-8 -classpath D:\IdeaProjects\JavaEE-enterprise-application-development-tutorial\chapter02\target\classes;D:\Environments\apache-maven-3.6.2\maven-repo\javax\annotation\jsr250-api\1.0\jsr250-api-1.0.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar com.awen.assemble.XmlBeanAssembleTest User [username=柳小子, password=123456, list=["constructorvalue1", "constructorvalue2"]] User [username=子小柳, password=654321, list=["setlistvalue1", "setlistvalue2"]] Process finished with exit code 0

从运行结果可以看出,已经成功地使用基于XML装配的构造注入和设值注入两种方式装配了User实例。

OK , 到了现在 , 我们彻底不用再去程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !

思考

user 对象是谁创建的 ?

【 user 对象是由Spring创建的 】

user 对象的属性是怎么设置的 ?

【user 对象的属性是由Spring容器设置的 】

这个过程就叫控制反转(IoC) :

控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的 反转 : 程序本身不创建对象 , 而变成被动的接收对象 . 依赖注入 : 就是利用set方法来进行注入的.

IOC是一种编程思想,由主动的编程变成被动的接收

可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .

基于注解(Annotation)的装配

除了通过设值注入(Setter Injection)和构造注入(Constructor Injection)实现IoC,还可以通过Spring提供的注解方法实现IoC,这也是企业开发过程中最常用的一种IoC实现方式。

在Spring中,尽管使用XML配置文件可以实现Bean的装配工作,但如果应用中有很多Bean时,会导致XML配置文件过于臃肿,给后续的维护和升级工作带来一定的困难。为此,Spring提供了对Annotation(注解)技术的全面支持。

Spring中定义了一系列的注解,常用的注解如下所示。

@Component:可以使用此注解描述Spring中的Bean,但它是一个泛化的概念,仅仅表示一个组件(Bean),并且可以作用在任何层次。使用时只需将该注解标注在相应类上即可。 @Repository:用于将数据访问层(DAO层)的类标识为Spring中的Bean,其功能与@Component相同。 @Service:通常作用在业务层(Service层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同。 @Controller:通常作用在控制层(如Spring MVC的Controller),用于将控制层的类标识为Spring中的Bean,其功能与@Component相同。 @Autowired:用于对Bean的属性变量、属性的setter方法及构造方法进行标注,配合对应的注解处理器完成Bean的自动配置工作。默认按照Bean的类型进行装配。 @Resource:其作用与Autowired一样。其区别在于@Autowired默认按照Bean类型装配,而@Resource默认按照Bean实例名称进行装配。@Resource中有两个重要属性:name和type。Spring将name属性解析为Bean实例名称,type属性解析为Bean实例类型。如果指定name属性,则按实例名称进行装配;如果指定type属性,则按Bean类型进行装配;如果都不指定,则先按Bean实例名称装配,如果不能匹配,再按照Bean类型进行装配;如果都无法匹配,则抛出NoSuchBeanDefinitionException异常。 @Qualifier:与@Autowired注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称由@Qualifier注解的参数指定。在上面几个注解中,虽然@Repository、@Service与@Controller功能与@Component注解的功能相同,但为了使标注类本身用途更加清晰,建议在实际开发中使用@Repository、@Service与@Controller分别对实现类进行标注

下面,通过一个案例来演示如何通过这些注解来装配Bean。

(1)在chapter02模块的src/main/java目录下,创建一个com.awen.annotation包,在该包中创建接口UserDao,并在接口中定义一个save()方法,如文件所示。文件 UserDao.java

package com.awen.annotation; public interface UserDao { public void save(); }

(2)在com.awen.annotation包中,创建UserDao接口的实现类UserDaoImpl,该类需要实现接口中的save()方法,如文件所示。文件 UserDaoImpl.java

package com.awen.annotation; import org.springframework.stereotype.Repository; @Repository("userDao") public class UserDaoImpl implements UserDao{ public void save(){ System.out.println("userdao...save..."); } }

在文件UserDaoImpl.java中,首先使用@Repository注解将UserDaoImpl类标识为Spring中的Bean,其写法相当于配置文件中的编写。然后在save()方法中输出打印一句话,用于验证是否成功调用了该方法。

(3)在com.awen.annotation包中,创建接口UserService,在接口中同样定义一个save()方法,如文件所示。文件UserService.java

package com.awen.annotation; public interface UserService { public void save(); }

(4)在com.awen.annotation包中,创建UserService接口的实现类UserServiceImpl,该类需要实现接口中的save()方法,如文件所示。文件 UserServiceImpl.java

package com.awen.annotation; import javax.annotation.Resource; import org.springframework.stereotype.Service; @Service("userService") public class UserServiceImpl implements UserService{ @Resource(name="userDao") private UserDao userDao; public void save() { //调用userDao中的save方法 this.userDao.save(); System.out.println("userservice....save..."); } }

在文件 UserServiceImpl.java中,首先使用@Service注解将UserServiceImpl类标识为Spring中的Bean,这相当于配置文件中的编写;然后使用@Resource注解标注在属性userDao上,这相当于配置文件中的写法;最后在该类的save()方法中调用userDao中的save()方法,并输出一句话。

(5)在com.awen.annotation包中,创建控制器类UserController,编辑后如文件所示。文件UserController.java

package com.awen.annotation; import org.springframework.stereotype.Controller; import javax.annotation.Resource; @Controller("userController") public class UserController { @Resource(name="userService") private UserService userService; public void save(){ this.userService.save(); System.out.println("userController...save..."); } }

在文件UserController.java中,首先使用@Controller注解标注了UserController类,这相当于在配置文件中编写;然后使用了@Resource注解标注在userService属性上,这相当于在配置文件中编写;最后在其save()方法中调用了userService中的save()方法,并输出一句话。

(6)在src/main/resources目录下,创建配置文件beans6.xml,在配置文件中编写基于Annotation装配的代码,如文件所示。文件 beans6.xml

从上述代码可以看出,文件beans6.xml与之前的配置文件有很大不同。首先,在元素中,增加了第4行,第7行和第8行中包含有context的约束信息;然后通过配置来开启注解处理器;最后分别定义了3个Bean对应所编写的3个实例。与XML装备方式有所不同的是,这里不再需要配置子元素。

上述Spring配置文件中的注解方式虽然较大程度简化了XML文件中Bean的配置,但仍需要在Spring配置文件中一一配置相应的Bean,为此Spring注解提供了另外一种高效的注解配置方式(对包路径下的所有Bean文件进行扫描),其配置方式如下。

所以可以将上述文件文件 beans6.xml中第9~16行代码进行如下替换(推荐)。

(7)在com.awen.annotation包中,创建测试类AnnotationAssembleTest,在类中编写测试方法并定义配置文件的路径,然后通过Spring容器加载配置文件并获取UserController实例,最后调用实例中的save()方法,如文件所示。文件 AnnotationAssembleTest.java

package com.awen.annotation; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class AnnotationAssembleTest { public static void main(String[] args) { // 定义配置文件路径 String xmlPath = "com/awen/annotation/beans6.xml"; // 加载配置文件 ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); // 获取UserController实例 UserController userController = (UserController) applicationContext.getBean("userController"); // 调用UserController中的save()方法 userController.save(); } }

总是出错 一叶障目

执行程序后,控制台的输出结果如图所示。

userdao...save... userservice....save... userController...save...

从运行结果可以看到,Spring容器已成功获取了UserController的实例,并通过调用实例中的方法执行了各层中的输出语句,这说明已成功实现了基于Annotation装配Bean

小提示上述案例中如果使用@Autowired注解替换@Resource注解,也可以达到同样的效果。

在这里插入图片描述

提示: 除了可以像示例中通过元素来配置Bean外,还可以通过包扫描的形式来配置一个包下的所有Bean:

自动装配

虽然使用注解的方式装配Bean,在一定程度上减少了配置文件中的代码量,但是也有企业项目中,是没有使用注解方式开发的,那么有没有什么办法既可以减少代码量,又能够实现Bean的装配呢?答案是肯定的,Spring的元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean。所谓自动装配,就是将一个Bean自动地注入到其他Bean的Property中。autowire属性有5个值,其值及说明如表所示。表元素的autowire属性值及说明

在这里插入图片描述

​ 自动装配,使用方式如下:

修改上一节UserServiceImple和UserController,分别增加类属性的setter方法;

修改Spring配置文件beans6.xml,将配置文件修改成自动装配形式,也就是使用autowire属性配置Bean;

重新测试程序。

上述配置文件中,用于配置userService和userController的元素中除了id和class属性外,还增加了autowire属性,并将其属性值设置为byName。在默认情况下,配置文件中需要通过ref来装配Bean,但设置了autowire="byName"后,Spring会自动寻找userService Bean中的属性,并将其属性名称与配置文件中定义的Bean做匹配。由于UserServiceImpl中定义了userDao属性及其setter方法,这与配置文件中id为userDao的Bean相匹配,所以Spring会自动地将id为userDao的Bean装配到id为userService的Bean中。执行程序后,控制台的输出结果如下所示。 从运行结果可以看出,使用自动装配同样完成了依赖注入

D:\Environments\jdk-11.0.2\bin\java.exe -javaagent:D:\Java\ideaIU-2019.2.win\lib\idea_rt.jar=5574:D:\Java\ideaIU-2019.2.win\bin -Dfile.encoding=UTF-8 -classpath D:\IdeaProjects\JavaEE-enterprise-application-development-tutorial\chapter02\target\classes;D:\Environments\apache-maven-3.6.2\maven-repo\javax\annotation\jsr250-api\1.0\jsr250-api-1.0.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-webmvc\5.2.3.RELEASE\spring-webmvc-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-aop\5.2.3.RELEASE\spring-aop-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-context\5.2.3.RELEASE\spring-context-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-expression\5.2.3.RELEASE\spring-expression-5.2.3.RELEASE.jar;D:\Environments\apache-maven-3.6.2\maven-repo\org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar com.awen.annotation.AnnotationAssembleTest userdao...save... userservice....save... userController...save... Process finished with exit code 0

手动装配

自动装配

自动装配是Spring满足bean依赖的一种方式! Spring会在上下文中自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式:

在xml中显式配置; 在java中显式配置; 隐式的自动装配bean 重要

Autowired 自动装配

ByName自动装配

ByType自动装配

小结:

byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致! byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

使用注解实现自动装配

jdk1.5支持注解,Spring2.5开始支持注解。

要使用注解须知:

导入约束:context约束。

配置注解的支持:context:annot-config/

@Autowired

直接在属性上使用即可!也可以在set方式上使用!

使用Autowired我们可以不用编写Set方法了,前提是你这个自动装配的属性在IoC(Spring)容器中存在,且符合名字byName!

科普:

@Nullable 字段标记了这个注解,说明这个字段可以为null public People(@Nullable String name){ this.name = name; } public @interface Autowired { boolean required() default true; }

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解@Autowired完成的时候,我们可以使用@Qualifier(value=“xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!

@Resource注解

小结:

@Resource和@Autowired的区别:

都是用来自动装配的,都可以放在属性字段上; @Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】 @Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错! 执行顺序不同:@Autowired通过byType的方式实现,@Resource默认通过byName的方式实现。

在spring4之后,要使用注解开发,必须要保证aop的包导入了。

使用注解需要导入context约束,增加注解的支持!

bean

属性如何注入

//等价于 //@Component 组件 @Component public class User { //相当于 public String name; @Value("小憨批") public void setName(String name){ this.name = name; } }

衍生的注解

@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!

dao【@Repository】 service【@Service】 controller【@Controller】

这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean!

自动装配

-@Autowired:自动装配通过类型,名字 如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx") -@Nullable:字段标记了这个注解,说明这个字段可以为null -@Resource:自动装配通过名字,类型

作用域

@Scope("singleton") public class User { //相当于 public String name; @Value("小憨批") public void setName(String name){ this.name = name; } }

小结

xml与注解:

xml更加万能,适用于任何场合!维护简单方便。 注解,不是自己的类使用不了,维护相对复杂!

xml与注解最佳实践:

xml用来管理bean; 注解只负责完成属性的注入; 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3