Spring

Spring————程序员的春天

当客户端向服务器发出请求时,服务器把得到的请求发送给控制器Servlet,而在Servlet中需要创建Service对象来调用业务层相关功能(故说控制器层Servlet依赖于业务层Service),而在Service中又需要创建数据库层DAO对象来对数据库进行操作(故说业务层Service依赖于数据库层DAO)。

思考:针对上述过程,我们需要考虑这样几个问题。1.Servlet、Service以及Dao对象的创建时间、创建数量。2.Servlet、Service以及Dao之间的依赖关系。如何处理这些问题呢?Spring就是用来处理对象的创建、以及对象之间依赖关系的一个开发框架。它打破了我们传统开发的观念,我们不再需要像以前那样在具体的类中创建具体的对象,而是将对象的创建交给它去完成。它是我们所要学习的框架中最重要的框架,请务必好好学习。

1.Spring框架中的专业术语

1.1组件/框架设计

  • 侵入式设计:对现有类的结构有影响,即需要实现或继承某些特定类。 如Struts框架。
  • 非侵入式设计:引入了框架,对现有的类结构没有影响。如Spring框架/Hibernate框架。

1.2控制反转

Inversion On Control,简称IOC。对象的创建交给外部容器自动完成,这个就叫做控制反转。(有控制反转就有控制正转,控制正转:对象的创建由我们自己创建)

依赖注入dependency injection,简称DI,用于处理对象间的依赖关系。

二者区别:控制反转(IOC):解决对象创建的问题,(对象的创建然后修改测试类:交给别人)。依赖注入(DI):在创建完对象后,对象关系的处理就是依赖注入,(通过set方法依赖注入。)

 

 

说明此时获取的两个User不再是同一个对象。

那么由IOC容器管理的pojo对象应该在何时创建呢?我们来看看,首先在User.java中添加一个无参构造器:

 

 

1.3AOP

面向切面编程。切面,简单来说可以理解为一个类,由很多重复代码形成的类。切面举例:事务、日志、权限。 关于AOP的详细讲解我推荐你们看这篇博客:Spring AOP实现原理与应用 .

 

2.Spring框架概述

Spring框架,可以解决对象创建以及对象之间依赖关系的一种框架。且可以和其它框架一起使用,例如spring与struts、spring和hibernate。(起到整合/粘合作用的一个框架)。

spring提供了一站式解决方案:
1)SpringCore:是Spring的核心功能:IOC容器,解决对象创建及依赖关系。
2)SpringWeb:Spring对web模块的支持。

可以与struts整合,让struts的action创建交给spring。
Spring mvc模式,用springmvc整合了就不用struts了。

3)Spring DAO:是Spring对Jdbc操作的支持。(Jdbc Template模块工具类)

4)Spring ORM:是Spring对ORM的支持。

既可以与hibernate整合(使用原始的session)
也可以使用Spring对Hibernate操作的封装(对上面的session又进行了一层封装)

5)Spring AOP:关于AOP的详细讲解我推荐你们看这篇博客:Spring AOP实现原理与应用 .

6)SpringEE:Spring对javaEE其它模块的支持

3.Spring开发步骤

1)导入jar包:



写在前面的话:当你运行程序出现org.springframework.beans.factory.BeanDefinitionStoreException的报错信息时,不要想了,出现这种报错的信息原因绝对是因为jdk版本和你导入的spring jar包不兼容的问题。由于spring3.x与jdk1.7兼容,而spring4.x与jdk1.8兼容,所以这里提供两种解决方案:

  • 1.将jdk版本调为1.7,我用的开发工具为IDEA,它默认下的JDK使用1.8版本,所以我需要在三个地方将jdk的版本改过来(前提是你已经下载了jdk1.7版本),修改IDEA配置中Project的jdk版本、Modules的jdk版本、SDKs的版本,如果你用到leTomcat还需要修改Tomcat配置的jdk版本。这样jdk1.7与spring3.x才兼容。
  • 2.将spring3.x.jar换成spring4.x.jar包。这种方式比较繁琐,建议大家使用第一种方式。spring4.x与jdk1.8才兼容。

2)配置核心文件applicationContext.xml(文件名称随意):


代码如下:

 
 

3)使用:

首先我们创建一个pojo对象User.java:


然后创建测试类使用这个User对象,以前我们要使用User对象时直接像这样 User user=new User();new一个对象即可:


而当我们使用Spring后就应该这样使用User对象,首先在applicationContext.xml中添加 <bean>标签,一个 <bean>标签代表一个pojo对象:


其中各个属性的说明见注释。然后我们通过如下步骤获取该pojo对象:



运行测试类:


说明成功获取到User对象。上述是通过工厂类获取的IOC容器创建的User对象,下面我们看看使用Spring框架获取pojo对象的第二种方式直接得到IOC容器的对象:

运行程序,成功打印出user信息,说明我们通过IOC容器成功获取到user对象。


 

4.<bean>创建的细节

对上述代码进行改进,对于IOC容器对象,我们只需创建一次即可,所以将创建IOC对象的代码改为成员变量。

 

代码中我们通过IOC对象创建了两个User对象,运行测试类得到打印结果:


发现答应的这两个User对象id都一样,说明我们获取到的是同一个对象,也说明通过 <bean>标签设置的pojo对象是单例的。为什么呢?其实 <bean>标签默认有一个 scope="singleton"的属性,代表该 <bean标签对象的pojo对象是单例的。我们可以将该属性值改为 scope="prototype",如下:

 
然后再运行测试类,输出如下内容:
 

说明此时获取的两个User不再是同一个对象。

那么由IOC容器管理的pojo对象应该在何时创建呢?我们来看看,首先在User.java中添加一个无参构造器:


然后修改测试类:

 
运行测试类:

从控制台中输出内容我们可以得知:当程序运行时,IOC容器首先创建,然后当我们需要得到IOC容器中的po打印台的内容说明该User对象在程序启动时就创建在IOC容器中了,不信我们把通过IOC容器得到User对象的代码注释掉再看输出结果:jo对象时我们通过语句 ac.getBean("user");得到,此时就会在IOC中创建由它管理的pojo对象。当我们删除 ac.getBean("user");语句时,再次运行程序,得到如下内容:
这说明什么呢?说明IOC容器中没有创建pojo对象(因为一旦创建就会有”—User对象创建—“的语句输出)。综上情况,即只有当我们用到pojo对象时,IOC容器才会在自己内部创建它。此种情况为 <bean>标签的属性为 scope="prototype"的结果,那么我们再来看看当属性为 scope="singleton"时的输出结果为:

 
 打印台的内容说明该User对象在程序启动时就创建在IOC容器中了,不信我们把通过IOC容器得到User对象的代码注释掉再看输出结果:


发现此时即使我们不通过ac.getBean("user");语句得到User对象,它也在程序启动时就创建了。

总结:在<bean>标签中设置bean对象为单例时,该对象在系统启动时就会创建;设置为多例时,该对象在我们需要使用时才创建。

 

4.1<bean>标签中的其它属性说明

  • 1.lazy-init:延迟初始化bean对象,默认值为false,即不延迟创建bean对象,在程序启动时就在IOC中创建bean对象;若其值为true则延迟创建bean对象,即在我们需要对象时才在IOC容器中创建该对象。此属性只对单例bean对象有效。
  • 2.init-method:可以给该属性传递一个在pojo对象中创建的方法例如A方法的方法名A作为init-method的属性值,表示当该pojo对象在IOC容器中被创建后就立刻执行这个A方法。
  • 3.destoy-method:同上,给该属性传递一个在pojo对象中创建的方法例如B方法的方法名B作为destoy-method的属性值,表示当IOC容器被销毁时(该pojo对象也会在IOC中销毁)会立刻调用这个B方法。当然我们通过ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");创建的IOC对象ac是没有destoy()方法的,我们需要这个创建IOC对象ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");这样创建出来的IOC对象才有destoy()方法。

5.Spring IOC容器

Spring IOC容器,是Spring的核心内容,用于创建对象和处理对象间的依赖关系。

5.1对象的创建

利用IOC容器创建对象的方式有如下几种:1.调用无参数构造器。2.调用带参数构造器。3.工厂创建对象。包括工厂类的静态方法创建对象和工厂类的非静态方法创建对象4.反射。(IOC的原理就是通过反射来创建对象)

5.1.1调用无参数构造器

在配置文件中加入如下内容:


 

5.1.2调用带参数构造器



<constructor-arg>标签中还有一个ref的属性,属性值代表引用配置文件(即IOC容器)中的相应对象。

故还可以采用这种方法调用带参数构造器创建对象:



5.1.3工厂创建对象

首先创建一个工厂类:



调用工厂的实例方法创建对象:



调用工厂静态方法创建对象:


5.2处理对象的依赖关系

在IOC容器的配置文件中我们有如下给对象注入属性的方法:1.通过构造方法。2.通过set方法给属性注入值。3.p名称空间。4.自动装配。5.注解。

5.2.1通过构造方法

首先我们来看看如何通过构造方法来给对象的属性赋值,在配置文件中添加如下标签即可通过构造器给该User对象的属性赋值:


5.2.2通过set方法

通过set方法给属性赋值,前提是在User对象中给它的属性添加了set方法:



接下来我们看个案例,以前我们开发时根据MVC模式都会像下面这样建立相应的Service.java、Servlet.java和dao.java:






都需要我们自己在.java文件中添加A a=new A();来创建其所需要的依赖对象,而现在我们就将对象的创建交给IOC了,选择set给属性赋值的方式来给它们注入其所需依赖对象,修改它们的代码:






然后我们需要在application.xml中进行配置:



ref的属性值代表给该对象注入它所依赖的对象,即我们上述讲到的依赖注入(dependency injection),通过上述步骤我们便完成了将对象的创建交给IOC的操作。

上述三个对象的创建我们需要写三个<bean>标签才能完成,接下来我将介绍第二种方法通过内部bean的操作一次性完成它们的创建以及它们之间的依赖关系,修改配置文件中的内容:





通过上述内部<bean>标签的方式我们便可实现和set注入依赖相同的效果。我们来看看它们两者的相同和区别:

  • 相同:都可以创建Service对象,并处理了之间的依赖关系。
  • 区别:set注入创建的Service对象可以给另一个Servlet对象调用,而内部bean将Service对象写在Servlet内部导致该Service对象只能被该Servlet使用,所以内部bean标签的使用场景在只需要一个Servlet对象的项目中。
5.2.3通过p名称空间给对象的属性注入值

此中方法只有在Spring3.0版本及以上版本才能用。首先在配置文件的<beans>根标签中加入属性:xmlns:p="http://www.springframework.org/schema/p"。然后我们便可以在配置文件中这样给对象的属性赋值:


当我们在配置文件中输入p:时,会出现两个属性1.p:userDao 和p:userDao-ref,这里有必要说明一下二者区别:

  • p:userDao:代表直接给UserService对象的userDao属性赋值
  • p:userDao-ref:代表引用的userDao对象

例如使用p名称空间给传统的对象属性赋值时我们这样写:



5.2.4.自动装配

当我们在配置文件中用<bean>标签指明相应对象的同时就将这个对象放入到了IOC容器中(其中标签中的id属性唯一指示一个对象),当我们给该bean标签添加了autowrite="byName"的属性后,对于该标签对应的对象注入的属性,会去IOC容器中自动查找与属性同名的对象。

例如如下代码:


通过上述三个<bean>标签我们就将userDao、userService、userServlet三个对象添加到了IOC容器中。我们在UserService对象的bean标签中加上了autowrite="byName"的属性,这样我们查看UserService.java的代码,它有一个UserDao对象名为userDao的属性,此时就会自动去IOC容器中寻找与userDao同名的对象(即在bean标签中寻找id为userDao的对象),然后进行注入,此时我们若将<bean id="userDao" class="pojo.UserDao">id="userDao"属性值改为userDao1或者其它名字,则运行系统会出现空指针异常,道理上述已分析。UserServlet注入userService的属性道理同此。

我们也可以将该属性定义到全局<beans>标签中,设置default-autowrite="byName"的属性,这样就不用每个bean标签中都写上autowrite="byName"属性了。

上述是根据名称自动装配,其实autowrite的属性值还可以为byType即根据类型自动装配。对于<bean id="userService" class="pojo.UserService">,当添加了autowrity="byType"的属性后,此时寻找它依赖的属性userDao的过程如下:查看UserService.java代码,它需要注入的属性类型为UserDao类型,所以就会自动去IOC容器中查找UserDao类型的对象并自动为UserService对象注入该属性,此时各bean标签的id属性值便可以随便写了如果根据类型自动装配,则要保证保证该类型的对象只有一个,否则会报错。该属性同样可以在全局beans标签中进行配置。

利用自动装配的优缺点:简化了配置,但不利用系统维护。所以一般不推荐此中用法,下面我们再来介绍第5中非常简单的配置。

5.2.5注解

注解方式可以简化Spring的IOC容器的配置。

使用步骤:

  • 1.先引入context名称空间
  • 2.开启注解扫描
  • 3.使用注解:通过注解的方式,把对象加入到IOC容器中。

首先在IOC配置文件中引入context名称空间,即在<beans>全局标签中添加xmlns:context="http://www.springframework.org/schema/context"属性。

然后在配置文件中添加如下标签


base-package:表示该扫描器只扫描此包下所有类。

最后我们便可以使用注解了,在pojo对象的.java文件中分别加入如下注解:



@Componet注解:代表将该对象放入到IOC容器中,括号里面的名字代表该对象在IOC容器中的唯一标识名字,名字任意取。该注解写在代码第一行。

@Resource注解:用于将该对象依赖的属性从IOC容器中找到并注入,括号里面的name属性值必须跟@Compenent注解里填入的名字相同。

通过注解方法便可去掉各.java文件中为属性创建设置的set方法。

继续对上述注解方式进行配置优化,去掉括号中的内容:






在测试类中运行依然可以正常运行。

说明:利用@Compenent注解的方式是通用的将对象加入到IOC容器中的方式,而有时候我们需要区别各层对象添加的方式,所以这里我们将Dao层对象添加到IOC容器的注解方式改为:@Repository表示持久层的组件;修改Service层对象添加到IOC容器的注解方式:@Service表示业务逻辑层的组件;修改Servlet层对象添加到IOC容器的注解方式为:@Controller表示控制层的组件。

另外需要说明的是使用注解的方式将对象添加到IOC容器中和在xml文件中添加配置的方式是可以共存的。但通过@Resource不带括号的注解,必须要保证该类型只有一个变量,所以一般情况下我们还是优先使用@Resource(name=””)注解。

到此,Spring框架的学习我们已完成。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值