




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第8章Spring框架基础掌握Spring框架的相关配置掌握Spring框架依赖注入的3种方式掌握Spring框架Bean的作用域和装配方式掌握Spring框架中的组件扫描及注解开发掌握Spring框架中AOP的开发学习目标8.1.1Spring框架的基本概念Spring框架是一个基于Java平台的轻量级、一站式构建企业级应用的解决方案,提供全面的基础架构支持开发Java应用程序。Spring框架提供了声明式事务管理、远程访问、Web服务,以及数据持久化等方面的技术支持。Spring框架的用途不仅局限于服务端的开发,任何Java应用都可以从中受益。Spring框架采用分层架构,根据不同的功能被划分成多个模块,这些模块大体可分为数据访问/集成层、Web层、AOP层、核心容器层和测试层5个模块(见图8-1)。Spring框架允许自由选择需要使用的模块,不必引入其余模块。8.1Spring框架的简介测试层:Test模块使用Junit框架或TestNG框架进行测试,提供对Spring应用的单元测试和集成测试支持。8.1Spring框架的简介图8-1Spring框架整体结构核心容器层(CoreContainer):Spring框架的核心容器是其他模块建立的基础部分,由Beans、Core、Context和ExpressionLanguage(SpEL)模块组成。Beans模块提供了BeanFactory接口,是工厂模式的经典实现,在Spring框架中,管理对象通常被称为Bean实例。Core核心模块提供了Spring框架的基本组成部分,包括控制反转(IoC)和依赖注入(DI)功能。Context上下文模块建立在Core模块和Beans模块的基础之上,是访问定义和配置任何对象的媒介。ExpressionLanguage模块是运行时查询和操作对象图的强大的表达式语言。AOP层:包括AOP、Aspects、Instrumentation、Messaging模块。AOP模块提供了面向切面的编程实现,允许定义方法拦截器和切入点,将代码按照功能进行分离,以降低模块之间的耦合性。Aspects模块提供了一个功能强大且成熟的面向切面编程的AspectJ框架的集成。Instrumentation模块提供了类工具的支持和类加载器的实现。Messaging模块提供了对消息传递体系的支持。8.1Spring框架的简介数据访问/集成层(DataAccess/Integration):包括JDBC、ORM、OXM、JMS和Transactions模块。JDBC模块提供了一个JDBC的抽象层,大幅减少了在开发过程中对数据库操作的编码。ORM模块为JPA、JDO、Hibernate和iBatis等数据库框架提供了集成方案,还提供了一个支持实体对象/XML映射的抽象层实现方案,如JAXB、Castor、XMLBeans、JiBX和XStream。JMS模块指的是Java消息服务,具有生产和消费信息的功能。Transactions模块是事务模块,支持编程和声明式事务管理。Web层:包括Web、Servlet、WebSocket和Portlet模块。Web模块提供了Web开发所需的必要组件,如多文件上传功能,可以使用Servlet监听器来初始化SpringIoC容器及Web应用上下文。Servlet模块提供了MVC模式的Web应用程序实现方法。Portlet模块提供了在Portlet环境中与Web服务相关的支持。8.1Spring框架的简介8.1.2在IDEA中配置Spring应用程序1.创建项目(1)首先打开IDEA,点击NewProject→Java,配置好Java的SDK后,单击“NEXT”按钮,得到如图8-2所示的窗口。图8-2IDEA中新建Java项目8.1Spring框架的简介(2)其次弹出是否创建模板选项,如图8-3所示,直接单击“Next”按钮跳过即可。(3)最后输入项目名称(Projectname),单击“Finish”按钮,如图8-4所示,此时完成项目的创建操作。8.1Spring框架的简介图8-3创建模板选项窗口图8-4项目名称修改窗口2.添加Spring框架支持共有两种添加Spring框架支持的方法。(1)方式一。①在IDEA中右击项目文件夹,单击“AddFrameworkSupport...”(见图8-5)。②在弹出的AddFrameworkSupport窗口左侧勾选Spring框架后,在右侧勾选Createemptyspring-config.xml选项和Download选项,如图8-6所示。8.1Spring框架的简介图8-5选择“AddFrameworkSupport...”8.1Spring框架的简介③单击“OK”按钮后,IDEA会自动下载Spring框架的依赖jar包,并创建一个空白的spring-config.xml配置文件,到这里Spring框架的开发环境已经配置完成,目录结构如图8-7所示。项目根目录下生成的lib文件夹就是Spring框架相关组件的jar包,src目录的spring-config.xml就是Spring框架的配置文件,后面编写的Java代码都放置在src目录下。图8-6打开的AddFrameworkSupport窗口图8-7项目的目录结构8.1Spring框架的简介(2)方式二。在方式一中,通过IDEA的AddFrameworkSupport窗口添加框架支持可供选择的方法版本有限,我们还可以通过另一种方式实现。①在根目录中创建一个libs文件夹,将从官网下载的Spring框架的相关jar包放入该文件夹下,右击libs文件夹,单击“AddasLibrary”,将其添加为项目的lib库,如图8-8所示。图8-8添加依赖库8.1Spring框架的简介②鼠标右击src目录,选择New→XMLConfigurationFile→SpringConfig,可以创建一个spring-config.xml配置文件,如图8-9所示。图8-9方式二中创建Spring配置文件8.2SpringIoC容器8.2.1SpringIoC容器概述控制反转(InversionofControl,IoC)能够将创建实例的权利反转给SpringIoC容器,由SpringIoC容器创建实例。这是面向对象编程的一种设计原则,可以用来降低计算机代码之间的耦合度。在软件工程中,耦合度指的是对象之间的依赖性,对象之间的耦合度越强,维护成本越高。耦合度的强弱取决于模块间接口的复杂性、调用模块的方式,以及通过界面传送数据的多少。当某个Java对象(调用者)需要调用另一个Java对象(被调用者,即被依赖对象)时,在传统程序中,调用者通常会采用new运算符创建一个对象,这种方式会导致调用者与被调用者之间的耦合度增强,不利于后期项目的升级和维护。调用者创建被调用者如图8-10所示。8.2SpringIoC容器图8-10调用者创建被调用者在使用Spring框架后,对象的实例不再由调用者创建,而是由SpringIoC容器创建,对象之间的关系由SpringIoC容器负责控制,不再由调用者控制。这样,对象之间的这种依赖关系由程序转移到SpringIoC容器,控制权发生了反转,这就是Spring框架的控制反转。从SpringIoC容器的角度看,SpringIoC容器负责将被依赖对象赋值给调用者的成员变量,这相当于调用者注入了它依赖的实例,这就是Spring框架的依赖注入,如图8-11所示。8.2SpringIoC容器图8-11由容器注入被调用者控制反转也被称为依赖注入(DependencyInjection,DI),是面向对象编程的一种设计理念,用来降低程序代码间的耦合度,在MVC的设计模式中经常使用。我们首先需要考虑什么是依赖。依赖在代码中一般指通过局部变量、方法参数、返回值等建立的对于其他对象的调用关系。例如,在A类的方法中,实例化了B类的对象并调用其方法以完成特定的功能,即A类依赖B类。SpringIoC容器实现了控制反转和依赖注入,使用某种形式的配置文件(可以用XML、Java注解或Java代码方式来编写)告诉SpringIoC容器要实例化、配置和组装应用程序中的哪些对象,这些对象在SpringIoC容器中被称为Bean。8.2SpringIoC容器在Spring框架中,BeanFactory接口和ApplicationContext接口都可以代表SpringIoC容器。其中最基本的接口就是BeanFactory接口,负责配置、创建、管理Bean。ApplicationContext接口是BeanFactory接口的子接口,也被称为Spring上下文。另外,ApplicationContext接口还是ResourceLoader接口的子接口,拥有加载配置文件的一些方法。ApplicationContext接口有以下实现类。(1)ClassPathXmlApplicationContext实现类从类路径下加载XML配置文件来初始化容器。(2)FileSystemXmlApplicationContext实现类从系统文件目录中加载XML配置文件来初始化容器。(3)AnnotationConfigApplicationContext实现类通过解析注解的方式来初始化容器。8.2SpringIoC容器例8-1SpringIoC容器的基本使用步骤。(1)编写Bean类的对象代码。在src目录下创建一个org.example.dao包来放置持久层类代码,在该包中创建一个UserDao类,添加一个getUserList()方法,代码如下。packageorg.example.dao;
//UserDao类
publicclassUserDao{
//获取用户列表方法
publicvoidgetUserList(){
//用输入语句来代替功能的执行
System.out.println("获取用户列表...");
}
}8.2SpringIoC容器(2)编写配置文件,装配bean。在Spring-config.xml配置文件中使用bean标签,以及bean标签的id属性给这个bean起别名,并使用class属性配置这个bean的全限定类名(包名.类名),代码如下。<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd">
<!--装配bean-->
<beanid="userDao"class="org.example.dao.UserDao"></bean>
</beans>编写上述配置文件后,Spring框架会根据bean标签中class属性的全限定类名找到org.example.dao包下的UserDao类,并新建(new)一个userDao对象,将其装配到SpringIoC容器中;使用id属性起的别名是这个bean在容器中的名称,后续从容器中获取bean时可以使用这个id名来获取。若没有定义id名,则SpringIoC容器在默认装配bean时用类名的首字母小写形式作为别名。8.2SpringIoC容器(3)创建SpringIoC容器对象,获取bean。①创建SpringIoC容器对象。首先创建一个org.example.test包来放置测试代码,在这个包中新建一个Test01测试类,在main()方法中使用ClassPathXmlApplicationContext类创建SpringIoC容器,传入配置文件名称,即“spring-config.xml”,由此便可通过读取类目录下的配置文件来初始化SpringIoC容器。②获取bean对象。可以通过SpringIoC容器的getBean()方法从容器中获取bean。传入的参数可以是字符串形式(配置文件中bean标签的id名),通过这种方式获取的对象是Object类型的对象,需要进行强制类型转换(向下转型);传入的参数也可以是类的字节码形式,通过这种方式获取的对象就是传入参数中指定类型的对象。Spring框架自动对这个对象进行了类型转换。8.2SpringIoC容器③执行Bean中的方法。通过获取的bean可以直接执行bean中的方法,代码如下。packageorg.example.test;
publicclassTest1{
publicstaticvoidmain(String[]args){
//创建SpringIoC容器:读取类目录下的配置文件
ApplicationContextcontext=newClassPathXmlApplicationContext("spring-config.xml");
//从SpringIoC容器中获取bean:通过配置文件bean标签的id名来获取对象,须进行强制类型转换
UserDaouserDao1=(UserDao)context.getBean("userDao");
userDao1.getUserList();
//从SpringIoC容器中获取bean:通过类的字节码来获取对象,无须进行强制类型转换
UserDaouserDao2=context.getBean(UserDao.class);
userDao2.getUserList();
}
}8.2SpringIoC容器getUserList()方法正常执行,执行结果如图8-12所示,说明通过配置文件bean标签的id名和类的字节码来获取对象的两种形式均可以获取bean,并执行bean中的方法。图8-12getUserList()方法正常执行的结果8.2SpringIoC容器例8-1通过ClassPathXmlApplicationContext实现类从类路径下加载XML配置文件来初始化容器;Spring框架还支持从系统文件目录中加载XML配置文件来初始化容器,需要使用FileSystemXmlApplicationContext实现类,代码形式如下。//创建SpringIoC容器:读取文件系统下的配置文件
ApplicationContextcontext=newFileSystemXmlApplicationContext("C:\\Users\\Jian\\IdeaProjects\\CH8\\CH8_EX1\\src\\spring-config.xml");基于Java配置类,AnnotationConfigApplicationContext实现类可通过解析注解的方式初始化SpringIoC容器,此时传入的参数是配置类的字节码文件,代码形式如下。//创建SpringIoC容器:读取Java配置类中的配置
ApplicationContextcontext=newAnnotationConfigApplicationContext(SpringConfig.class);由于这些实现类都是ApplicationContext类的子类,所以从容器中获取Bean都是通过getBean()方法实现的。8.2SpringIoC容器8.2.2SpringIoC容器的设计在Spring框架中,bean是一个广义的概念,任何的Java对象、Java组件(包括数据源、事务管理器等)都被当成bean来处理。SpringIoC容器除负责创建bean外,还要管理bean之间的依赖关系。SpringIoC容器的设计思想是应用程序类与配置文件相结合,如图8-13所示。配置文件中记录了Spring框架要创建的bean及bean之间的依赖关系等内容,由SpringIoC容器创建并管理对象。当要使用这些bean时,可以直接从SpringIoC容器提供的方法中获取。图8-13SpringIoC容器的设计思想8.2SpringIoC容器狭义上的SpringIoC容器,在底层源码上就是一个Map集合。这个Map集合存储的键(key)是当前bean的别名,若不指定,则默认将class类名的首字母小写作为key,bean信息作为值(value)。存储bean的Map集合在DefaultListableBeanFactory类中。DefaultListableBeanFactory类的部分源码如下。/**Mapofbeandefinitionobjects,keyedbybeanname.*/privatefinalMap<String,BeanDefinition>beanDefinitionMap=newConcurrentHashMap<>(256);当SpringIoC容器扫描到Bean时,会将这个bean的描述信息以包名加类名的方式存到beanDefinitionMap中,而value是bean的定义对象beanDefinition,存储的是类的定义(描述信息)。8.2SpringIoC容器SpringIoC容器在启动的过程中,对bean进行初始化、实例化时,大致分为两步:第一步将class文件转换为beanDefinition对象,第二步根据beanDefinition对象,按照配置的要求进行初始化、实例化。SpringIoC容器为什么不在扫描到class文件后,立即进行初始化、实例化呢?这是因为在Spring框架提供的容器管理功能中,某些class类并不需要立刻初始化,如原型bean(作用域设置为prototype的bean)是在需要使用时初始化的。beanDefinitionMap中的beanDefinition对象相当于一个中转站,存放了bean的所有信息(包含作用域范围),在初始化时根据beanDefinition对象的属性信息进行。8.2SpringIoC容器SpringIoC容器在启动的过程中,对bean进行初始化、实例化时,大致分为两步:第一步将class文件转换为beanDefinition对象,第二步根据beanDefinition对象,按照配置的要求进行初始化、实例化。SpringIoC容器为什么不在扫描到class文件后,立即进行初始化、实例化呢?这是因为在Spring框架提供的容器管理功能中,某些class类并不需要立刻初始化,如原型bean(作用域设置为prototype的bean)是在需要使用时初始化的。beanDefinitionMap中的beanDefinition对象相当于一个中转站,存放了bean的所有信息(包含作用域范围),在初始化时根据beanDefinition对象的属性信息进行。8.2SpringIoC容器8.2.3Spring框架中的依赖注入每个软件都是由很多“组件”构成的。这里的“组件”是指广义的组件—组成部件,它可能是函数,可能是类,可能是包,也可能是微服务。软件的架构就是组件和组件之间的关系;而这些组件和组件之间的关系,就是广义的依赖关系。依赖注入就是将一个bean和它依赖的对象连接在一起的过程。假如Pen类有write()方法,用来表示笔的书写功能;Student类有study()方法,用来表示学生的学习动作。下面我们讨论学生学习需要用到笔的情况。publicclassPen{
publicvoidwrite(){
System.out.println("penwrite...");
}
}publicclassStudent{
privatePenpen;
publicvoidstudy(){
System.out.println("studentstudy...");
pen.write();
}
}8.2SpringIoC容器这里只定义了Student类与Pen类之间的依赖关系,但是并没有给Student类传入Pen类的实例对象,直接新建(new)一个student对象调用study()方法就会出现NullPointerException异常。要想使代码正常执行,可以继续完善Student类的代码,通过构造器参数及setter()方法注入Pen类的实例对象。完善后的Student类代码如下。publicclassStudent{
privatePenpen;
//setter方法和getter方法
publicPengetPen(){
returnpen;
}
publicvoidsetPen(Penpen){
this.pen=pen;
}
//构造器方法
publicStudent(){
}
publicStudent(Penpen){
this.pen=pen;
}
publicvoidstudy(){
System.out.println("studentstudy...");
pen.write();
}
}8.2SpringIoC容器接下来编写一个测试代码,学习在Java代码中是如何进行依赖注入的。在测试代码中,首先在testConstructorDI()方法中编写构造器注入的代码,也就是简单地在创建对象时传入依赖的对象实例;其次在testSetterDI()方法中编写Setter注入的代码,这里通过Setter方法传入依赖的对象实例;最后分别在main()函数中调用这些方法。测试代码如下。publicclassTestDemo{
//构造器注入测试方法
publicstaticvoidtestConstructorDI(){
Penpen=newPen();
Studentstudent=newStudent(pen);
student.study();
}
//Setter注入测试方法
publicstaticvoidtestSetterDI(){
Penpen=newPen();
Studentstudent=newStudent();
student.setPen(pen);
student.study();
}
//在main()函数中执行测试方法
publicstaticvoidmain(String[]args){
System.out.println("构造器注入测试:");
testConstructorDI();
System.out.println("分割线");
System.out.println("Setter方法注入测试:");
testSetterDI();
}
}8.2SpringIoC容器study()方法和write()方法成功执行,执行结果如图8-14所示,可以看到,Java中这种简单的依赖注入的形式,直接在代码中将两个对象连接在一起。当把一个bean交给SpringIoC容器管理时,它依赖的对象同样要在构造器参数、对象实例化之后,通过Setter方法注入其属性或方法参数。但是在Spring框架中则不必手动创建对象,而是在配置文件中描述如何创建它们;不必在代码中直接将对象连接在一起,而是在配置文件中描述哪些对象需要哪些服务,再由SpringIoC容器将它们连接在一起。图8-14study()方法和write()方法成功执行的执行结果8.2SpringIoC容器study()方法和write()方法成功执行,执行结果如图8-14所示,可以看到,Java中这种简单的依赖注入的形式,直接在代码中将两个对象连接在一起。当把一个bean交给SpringIoC容器管理时,它依赖的对象同样要在构造器参数、对象实例化之后,通过Setter方法注入其属性或方法参数。但是在Spring框架中则不必手动创建对象,而是在配置文件中描述如何创建它们;不必在代码中直接将对象连接在一起,而是在配置文件中描述哪些对象需要哪些服务,再由SpringIoC容器将它们连接在一起。图8-14study()方法和write()方法成功执行的执行结果8.3.1构造器注入基于构造函数的依赖注入是通过容器调用具有参数的构造方法,构造方法中的每个参数都表示一个依赖项。在Spring框架中,构造器可以通过形参名称、形参位置、形参类型注入依赖。这些注入的参数可以是基本类型,也可以是引用类型(包含SpringIoC容器中的bean)。8.3依赖注入的3种方式例8-2演示Spring框架中构造器注入的基本使用方法。(1)编写bean的代码。在src目录下的org.example.dao包中编辑UserDao类代码,添加name字段和age字段,添加构造方法。publicclassUserDao{
privateStringname;
privateIntegerage;
//省略了getter和setter方法
//获取用户列表
publicvoidgetUserList(){
//用打印一段话来模拟获取用户列表功能的执行
System.out.println("获取用户列表...");
}
//构造器函数
publicUserDao(Stringname,Integerage){
this.name=name;
this.age=age;
}
}(2)编写spring-config.xml配置文件,装配bean。①方式一:根据构造器的形参名称形式注入,在XML配置文件中编写如下代码。8.3依赖注入的3种方式<beanid="userDao"class="org.example.dao.UserDao">
<constructor-argname="name"value="张三"></constructor-arg>
<constructor-argname="age"value="18"></constructor-arg>
</bean>②方式二:根据构造器的形参位置注入,在XML配置文件中编写如下代码。<beanid="userDao"class="org.example.dao.UserDao">
<constructor-argindex="0"value="张三"></constructor-arg>
<constructor-argindex="1"value="18"></constructor-arg>
</bean>③方式三:根据构造器的形参类型注入,在XML配置文件中编写如下代码。<beanid="userDao"class="org.example.dao.UserDao">
<constructor-argtype="java.lang.String"value="张三"></constructor-arg>
<constructor-argtype="java.lang.Integer"value="18"></constructor-arg>
</bean>④方式四:注入SpringIoC容器中的其他bean。这里还需要添加其他bean的代码,以及在UserDao类中添加这个Bean类型字段,并完善构造器方法。在src目录下的org.example.dao包中添加一个OrderDao类,并在UserDao类中添加一个OrderDao类,以及一个含OrderDao参数的构造器方法。8.3依赖注入的3种方式publicclassUserDao{
privateStringname;
privateIntegerage;
privateOrderDaoorderDao;
//
添加字段
//省略getter和setter方法
//
省略userDao原有方法
//添加包含orderDao字段的构造器方法
publicUserDao(Stringname,Integerage,OrderDaoorderDao){
this.name=name;
this.age=age;
this.orderDao=orderDao;
}
}publicclassOrderDao{
//创建订单方法
publicvoidcreateOrder(){
//使用输出语句模拟创建订单功能
System.out.println("创建订单...");
}
}在spring-config.xml配置文件中装配OrderDao类和UserDao类,在装配UserDao类时使用含OrderDao字段的构造器方法,代码如下。8.3依赖注入的3种方式<beanid="orderDao"class="org.example.dao.OrderDao"></bean>
<beanid="userDao"class="org.example.dao.UserDao">
<constructor-argname="name"value="张三"></constructor-arg>
<constructor-argname="age"value="18"></constructor-arg>
<constructor-argname="orderDao"ref="orderDao"></constructor-arg>
</bean>publicclassTest1{
publicstaticvoidmain(String[]args){
//创建SpringIoC容器:读取类目录下的配置文件
ApplicationContextcontext=newClassPathXmlApplicationContext("spring-config.xml");
//从SpringIoC容器中获取bean
UserDaouserDao=context.getBean(UserDao.class);
userDao.getUserList();
System.out.println(userDao.getName());
System.out.println(userDao.getAge());
//执行OrderDao中方法
OrderDaoorderDao=userDao.getOrderDao();
orderDao.createOrder();
}
}测试代码执行结果8.3.2Setter注入基于Setter方法的依赖注入(Setter注入)是指通过bean中的Setter方法给对象注入依赖项。首先,在bean中需要保证有Setter方法来接受注入的依赖对象,其次,在Spring框架的XML配置文件中的bean标签下,通过property标签描述依赖注入的方式。8.3依赖注入的3种方式例8-3演示Spring框架中Setter注入的基本使用方法。(1)编写bean的代码。以org.example.dao包中的UserDao类为例,补充UserDao类中各字段的Setter方法和Getter方法,代码如下。publicclassUserDao{
privateStringname;
privateIntegerage
privateOrderDaoorderDao;
//省略getter和settter方法
//获取用户列表
publicvoidgetUserList(){
//用打印一段话来模拟获取用户列表功能的执行
System.out.println(“获取用户列表...”);
}
//补充无参构造器函数
publicUserDao(){
}
}(2)编写spring-config.xml配置文件,装配bean,代码如下。8.3依赖注入的3种方式<beanid="orderDao"class="org.example.dao.OrderDao"></bean>
<beanid="userDao"class="org.example.dao.UserDao">
<!--使用setter方法注入-->
<propertyname="name"value="张三"></property>
<propertyname="age"value="100"></property>
<propertyname="orderDao"ref="orderDao"></property>
</bean>publicclassTest1{
publicstaticvoidmain(String[]args){
//创建SpringIoC容器:读取类目录下的配置文件
ApplicationContextcontext=newClassPathXmlApplicationContext("spring-config.xml");
//从SpringIoC容器中获取bean
UserDaouserDao=context.getBean(UserDao.class);
userDao.getUserList();
System.out.println(userDao.getName());
System.out.println(userDao.getAge());
//执行OrderDao中方法
OrderDaoorderDao=userDao.getOrderDao();
orderDao.createOrder();
}
}测试代码执行结果8.3.3接口注入接口注入和Setter注入类似,都是通过特定的方法注入被依赖对象,二者的主要区别为:在Setter注入中,需要在类中实现Setter方法,并使用Setter方法注入依赖对象,被注入的具体对象是在配置文件中使用<property>标签定义的;而在接口注入中,需要实现特定的BeanFactoryAware接口,使用该接口提供的setBeanFactory()方法注入依赖对象,被注入的具体对象是在setBeanFactory()方法中定义的。例8-4演示Spring框架中接口注入的基本使用方法。(1)编写bean的代码。这里仍使用之前org.example.dao包中创建的OrderDao类,同时新建一个UserDao2类实现BeanFactoryAware接口,并使用setBeanFactory()方法注入依赖对象,代码如下。8.3依赖注入的3种方式8.3依赖注入的3种方式publicclassUserDao2implementsBeanFactoryAware{
privateStringname;
privateIntegerage;
privateOrderDaoorderDao;
//创建订单方法
publicvoidcreateOrder(){
//调用orderDao对象中的方法
this.orderDao.createOrder();
}
@Override
publicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{
this.name="张三";
this.age=18;
//这里是从容器中获取bean
OrderDaoorderDao=beanFactory.getBean(OrderDao.class);
this.orderDao=orderDao;
}
}(2)编写spring-config.xml配置文件,装配bean,代码如下。<beanid="orderDao"class="org.example.dao.OrderDao"/>
<beanid="userDao"class="org.example.dao.UserDao2"/>由于UserDao2类已经通过BeanFactoryAware接口的setBeanFactory()方法注入了依赖,所以这里只需要进行bean的装配。(3)编写测试代码。在测试代码中创建容器,并从SpringIoC容器中获取userDao2对象,然后调用createOrder()方法,代码如下。8.3依赖注入的3种方式publicclassTest2{
publicstaticvoidmain(String[]args){
//创建容器
ApplicationContextcontext=newClassPathXmlApplicationContext("spring-config.xml");
//从容器中获取Bean
UserDao2userDao2=context.getBean(UserDao2.class);
//执行Bean中的方法
userDao2.createOrder();
}
}图8-15createOrder()方法成功执行的执行结果createOrder()方法成功执行,执行结果如图8-15所示,使用接口注入方式并没有在XML配置文件中定义依赖关系,可见通过BeanFactoryAware接口使用setBeanFactory()方法同样能够完成依赖的注入。这种方法的依赖注入是硬编码在bean中的,侵入性较强,在项目开发中使用较少,了解即可。8.4.1作用域的分类Spring框架中主要有5种类型的作用域,分别是singleton、prototype、request、session、global-session。Spring框架中的作用域描述如表8-1所示。8.4bean的作用域作用域描述singleton默认作用域,将bean的作用域定义为在SpringIoC容器中以单例形式存在prototype将bean的作用域定义为在SpringIoC容器中以多例形式存在request将bean的作用域定义为在一个HTTP请求的生命周期内有效。每次HTTP请求后都会创建一个新的bean,仅用于WebApplicationContext环境session将bean的作用域定义为在一个HTTP会话的生命周期内有效。同一个HTTP会话共享一个bean,仅用于WebApplicationContext环境global-session类似于标准的HTTPSession作用域,不过它仅在基于portlet的Web应用程序中才有意义表8-1Spring框架中的作用域描述8.4.2singletonsingleton是Spring框架中默认的作用域,若在bean标签中没有定义scope属性,则Spring框架默认会以单例模式创建bean。单例模式就是采取一定的方法保证在整个软件系统中,某个类只能存在一个对象实例,且该类只提供一个取得其实例的方法。在Java中定义一个简单的单例类需要以下步骤:①私有化构造器;②在类内部创建对象实例;③提供一个共有的静态方法返回实例对象。8.4bean的作用域classSingleton{
//构造器私有化
privateSingleton(){
}
//在本类内部创建对象实例
privatefinalstaticSingletoninstance=newSingleton();
//提供一个公有的静态方法,返回实例对象
publicstaticSingletongetInstance(){
returninstance;
}
}例8-5演示Java中单例类的创建。(1)编写单例类Singleton,代码如下。(2)测试代码如下。首先定义一个测试方法,多次获取Singleton类的实例,其次打印输出对象的地址值。测试代码运行结果如图8-16所示,singleton1和singleton2输出的对象地址值相同,这就表示这里的类是单例类,创建的对象是单例对象。8.4bean的作用域publicclassTest3{
publicstaticvoidmain(String[]args){
Singletonsingleton1=Singleton.getInstance();
Singletonsingleton2=Singleton.getInstance();
System.out.println(singleton1);
System.out.println(singleton2);
}
}图8-16singleton1和singleton2输出对象地址值相同Spring框架提供了更为简洁的创建单例对象的方法,默认创建的对象就是单例对象,也可以在bean标签中通过scope属性设置为单例模式。例8-6演示Spring框架中单例模式的使用。(1)编写bean的代码。这里使用的是之前org.example.dao包中创建的OrderDao类,代码如下。(2)编写spring-config.xml配置文件,装配bean。8.4bean的作用域publicclassOrderDao{
//创建订单方法
publicvoidcreateOrder(){
//使用输出语句来模拟创建订单功能
System.out.println("创建订单...");
}
}<!--默认是单例作用域-->
<beanid="orderDao"class="org.example.dao.OrderDao"></bean><!--显式声明scope为单例作用域-->
<beanid="orderDao"class="org.example.dao.OrderDao"
scope="singleton"></bean>或者(3)测试代码如下。测试代码运行结果如图8-17所示,orderDao1和orderDao2输出的对象地址值相同,可见两次从SpringIoC容器中获取的orderDao对象是同一个(引用地址值相同)。8.4bean的作用域publicclassTest3{
publicstaticvoidmain(String[]args){
ApplicationContextcontext=newClassPathXmlApplicationContext("spring-config.xml");
OrderDaoorderDao1=context.getBean(OrderDao.class);
OrderDaoorderDao2=context.getBean(OrderDao.class);
System.out.println(orderDao1);
System.out.println(orderDao2);
}
}图8-17orderDao1和orderDao2输出对象地址值相同8.4.3prototypeprototype作用域会将bean定义为在SpringIoC容器中以多例形式存在的对象,即每次从SpringIoC容器中获取prototype作用域的bean时,都会创建一个新的实例。在XML配置文件的bean标签中将scope属性设置为prototype,就表示这个bean是多例的。8.4bean的作用域例8-7演示Spring框架中的prototype作用域。(1)编写bean的代码。这里仍然使用之前org.example.dao包中创建的OrderDao类。(2)编写spring-config.xml配置文件,装配bean。publicclassOrderDao{
//创建订单方法
publicvoidcreateOrder(){
//使用输出语句来模拟创建订单功能
System.out.println("创建订单...");
}
}<!--声明scope为prototype作用域-->
<beanid="orderDao"class="org.example.dao.OrderDao"scope="prototype"></bean>(3)测试代码如下。测试代码运行结果如图8-18所示,orderDao1和orderDao2输出的对象的地址值不同,可见设置scope为prototype后,从SpringIoC容器中多次获取的对象不是同一个(引用地址值不同)。8.4bean的作用域publicclassTest3{
publicstaticvoidmain(String[]args){
ApplicationContextcontext=newClassPathXmlApplicationContext("spring-config.xml");
OrderDaoorderDao1=context.getBean(OrderDao.class);
OrderDaoorderDao2=context.getBean(OrderDao.class);
System.out.println(orderDao1);
System.out.println(orderDao2);
}
}图8-18orderDao1和orderDao2输出的对象的地址值不同8.5.1基于XML装配beanSpring框架基本的XML配置文件可以在beans标签内添加bean标签来装配bean。bean标签的常用属性说明如表8-2所示。8.5Spring框架中bean的装配方式属性名称说明idbean的唯一标识名,必须以字母开头,且不能包含特殊字符name用来为bean指定一个或多个别名,且能包含特殊字符。若bean没有id,则name可被当作id使用class用来定义类的全限定名(包名+类名)。scope设置bean的作用域init-methodbean的初始化方法,在对象创建时被调用destroy-methodbean的销毁方法,在对象被销毁或容器关闭时被调用factory-bean配置bean工厂的实例对象factory-method配置bean的工厂方法表8-2bean标签的常用属性说明bean标签内有constructor-arg标签和property标签:constructor-arg标签通过构造器进行依赖注入,常用的属性说明如表8-3所示。property标签上常用的属性有name、ref、value,使用方式与在constructor-arg标签上的相同。8.5Spring框架中bean的装配方式属性名称说明name构造器注入时按照形参名称注入type构造器注入时按照形参类型注入index构造器注入时按照形参位置注入ref注入已经在SpringIoC容器中的bean对象value要注入的属性值表8-3constructor-arg标签上常用的属性说明例8-8演示bean标签中init-method、destroy-method、factory-method属性的使用。(1)编写bean的代码。这里仍然使用之前org.example.dao包中创建的OrderDao类,添加了init()初始化方法、destroy()销毁方法及getOrderDao()工厂方法,代码如下。(2)编写spring-config.xml配置文件,装配bean。8.5Spring框架中bean的装配方式publicclassOrderDao{
//创建订单方法
publicvoidcreateOrder(){
//使用输出语句模拟创建订单功能
System.out.println("创建订单...");
}
//初始化方法
publicvoidinit(){
System.out.println("初始化方法...");
}
//销毁方法
publicvoiddestroy(){
System.out.println("销毁方法...");
}
//创建OrderDao对象的工厂方法
publicstaticOrderDaogetOrderDao(){
System.out.println("getOrderDao方法执行...");
returnnewOrderDao();
}
}<beanid="orderDao"class="org.example.dao.OrderDao"init-method="init"destroy-method="destroy"
factory-method="getOrderDao"></bean>(3)测试代码如下。在这个测试代码中创建了容器,获取了orderDao对象,然后使用close()方法关闭了容器。测试代码运行结果如图8-19所示,init()方法、destroy()方法和getOrderDao()方法成功执行,可见这里Spring框架通过factory-method方法指定的工厂方法创建orderDao对象,并且在创建对象时执行了init-method指定的初始化方法,在容器关闭时执行了destroy-method指定的销毁方法。8.5Spring框架中bean的装配方式publicclassTest4{
publicstaticvoidmain(String[]args){
ClassPathXmlApplicationContextcontext=newClassPathXmlApplicationContext("spring-config.xml");
OrderDaoorderDao=context.getBean(OrderDao.class);
//关闭容器,使orderDao对象中的销毁方法能够触发
context.close();
}
}图8-19测试代码运行结果8.5.2基于组件扫描注解装配beanSpring框架支持基于组件扫描注解装配bean的方式,通过装配bean相关的注解@Component,可以简化配置,提升开发效率。要使Spring框架能够识别相应的注解,需要配置组件扫描,有通过XML配置文件开启组件扫描和基于Java配置类开启组件扫描两种方式。(1)方式一:通过XML配置文件开启组件扫描。例8-9演示通过XML配置文件开启组件扫描。①编写bean的代码。这里在org.example.dao包中创建了两个简单的bean,然后分别在UserDao类及OrderDao类上添加@Component注解,表明在扫描Spring组件时要将这些bean装配到容器中,代码如下。8.5Spring框架中bean的装配方式②编写spring-config.xml配置文件,开启组件扫描。在XML配置文件中,通过context:component-scan标签的base-package属性配置要扫描的包为org.example包,这样Spring框架会扫描org.example包(包含其子包)下所有配置了装配相关注解的bean,代码如下。8.5Spring框架中bean的装配方式<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xmlns:context="/schema/context"
xsi:schemaLocation="/schema/beans
/schema/beans/spring-beans.xsd
/schema/context
/schema/context/spring-context.xsd">
<!--开启组件扫描,配置要扫描的包为org.example包-->
<context:component-scanbase-package="org.example"/>
</beans>@Component
publicclassOrderDao{
publicvoidcreateOrder(){
System.out.println("创建订单...");
}
}@Component
publicclassUserDao{
publicvoidcreateUser(){
System.out.println("创建用户...");
}
}
注意,这里要使用context系列的标签,就需要添加对应的xsd约束。③测试代码如下。测试代码运行结果如图8-20所示,createUser()方法和createOrder()方法成功执行。从测试结果来看,UserDao类和OrderDao类中的方法都能够正常执行。我们只在XML配置文件中开启了组件扫描,以及在要装配的bean上使用了注解,这种基于组件扫描注解的方式很大程度上简化了开发,让我们不必在XML配置文件中进行烦琐的装配操作。8.5Spring框架中bean的装配方式publicclassSpringDemoTest{
publicstaticvoidmain(String[]args){
//创建容器
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 文具及类似用品战略市场规划报告
- 自动络筒机市场分析及竞争策略分析报告
- 包服务合同范本
- 企业股东股权合同范本
- 变更属于合同范本
- 世界红十字日纪念演讲稿
- 中药炮制工中级练习题及参考答案
- 少年儿童健康试题(附参考答案)
- 建筑制图及识图模拟习题及参考答案
- 《风筝》大班教案
- 2024~2025学年度八年级数学上册第1课时 负整数指数幂教学设计
- 2024年江西省吉安市遂川县初中教师业务素养检测试卷历史试题
- 2024至2030年中国特钢行业“十四五”分析及发展前景预测研究分析报告
- 小儿急性肠炎查房课件
- DL∕T 2024-2019 大型调相机型式试验导则
- 2024年苏州市职业大学单招职业适应性测试题库附答案
- 术后恶心呕吐防治专家意见
- MOOC 医学免疫学-南昌大学 中国大学慕课答案
- JB-T 8640-2014 额定电压26-35kV及以下电力电缆附件型号编制方法
- 社会保障卡办理委托书
- 微积分(第三版)课件:多元函数微积分
评论
0/150
提交评论