首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

你绝对需要的Spring学习笔记 整合部分SSH

目 录

一、 Spring概述1

1.1 Spring框架的作用1

1.2 Spring框架的优点1

1.3 Spring框架的容器1

二、 Spring容器的基本应用2

2.1如何将一个Bean组件交给Spring容器2

2.2如何获取Spring容器对象和Bean对象2

2.3如何控制对象创建的模式2

2.4 Bean对象创建的时机2

2.5为Bean对象执行初始化和销毁方法2

2.6案例:Spring框架的使用以及2.1节-2.5节整合测试3

三、 Spring框架IoC特性5

3.1 IoC概念5

3.2 DI概念5

3.3案例:测试IoC(set注入)5

3.4案例:测试IoC(构造注入)6

3.5案例:不用JDBC访问数据库,而是采用Hibernate访问6

Java

四、 Spring中各种类型的数据注入7

4.1 Bean对象注入7

4.2基本数据的注入7

4.3集合的注入7

4.4案例:各类数据注入7

五、 AOP概念10

5.1什么是AOP10

5.2 AOP和OOP的区别10

5.3 AOP相关术语10

5.4案例:AOP的使用,模拟某些组件需要记录日志的功能11

5.5通知类型11

5.6切入点12

5.7案例:环绕通知,修改5.4案例使之动态显示所执行的操作12

5.8案例:利用AOP实现异常处理,将异常信息写入文件13

六、 Log4j日志记录工具14

6.1 Log4j介绍14

6.2 Log4j的使用14

6.3案例:修改5.8案例,使用Log4j记录日志14

一、Spring概述

1.1 Spring框架的作用

Spring框架主要负责技术整合(可以整合很多技术),该框架提供IoC和AOP机制,基于这些特性整合,可以降低系统组件之间的耦合度,便于系统组件的维护、扩展和替换。

1.2 Spring框架的优点

其实与Spring框架的作用相同:

在SSH中,主要是利用Spring容器管理我们程序中的Action、DAO等组件,通过容器的IoC机制,可以降低Action、DAO之间的耦合度(关联度),利用AOP进行事务管理等共通部分的处理。

在SSH中,Struts2主要是利用它的控制器,而不是标签、表达式;Hibernate主要利用它的数据库访问;Spring主要是利用它的整合。

1.3 Spring框架的容器

Spring框架的核心是提供了一个容器(是我们抽象出来的,代指后面的类型)。该容器类型是BeanFactory或ApplicationContext(建议用这个类型,它是BeanFactory的子类,功能更多)。

该容器具有以下功能:

1)容器可以创建和销毁组件对象,等价于原来“工厂”类的作用。

2)容器可以采用不同的模式创建对象,如单例模式创建对象。

3)容器具有IoC机制实现。

4)容器具有AOP机制实现。

Java

二、

Spring容器的基本应用

2.1如何将一个Bean组件交给Spring容器

1)Bean组件其实就是个普通的Java类!

2)方法:在applicationContext.xml中添加以下定义,见2.6案例中step4。

2.2如何获取Spring容器对象和Bean对象

1)实例化容器:

ApplicationContext ac=new ClassPathXmlApplicationContext("/applicationContext.xml");

//FileSystemXmlApplicationContext("");//去指定的磁盘目录找,上面的为去Class路径找

2)利用getBean("标识符")方法获取容器中的Bean对象。见2.6案例中step5。

2.3如何控制对象创建的模式

Spring支持singleton(单例)和prototype(原型,非单例)两种模式。

默认是singleton模式,可以通过的scope属性修改为prototype模式。以后在Web程序中,通过扩展可以使用request、session等值。见2.6案例中step4、step7。

例如:

u 注意事项:对于NetCTOSS项目,一个请求创建一个Action,所以用Spring时必须指明prototype,否则默认使用singleton会出问题。而DAO则可用singleton模式。

2.4 Bean对象创建的时机

1)singleton模式的Bean组件是在容器实例化时创建。

2)prototype模式是在调用getBean()方法时创建。

3)singleton模式可以使用元素的lazy-init="true"属性将对象的创建时机推迟到调用getBean()方法。也可以在(根元素)中使用default-lazy-init="false"推迟所有单例Bean组件的创建时机。见2.6案例中step3、step4。

例如:

2.5为Bean对象执行初始化和销毁方法

1)初始化:可以利用元素的init-method="方法名"属性指定初始化方法。

指定的初始化方法是在构造方法调用后自动执行。若非单例模式,则每创建一个对象,则执行一次初始化方法(单例、非单例模式都可)。见2.6案例中step3、step4。

u 注意事项:

v 初始化的三种方式:写构造方法中;或写{ }中(代码块);Spring框架中元素写init-method="方法名"属性。

v 初始化不能用static{ },它是类加载调用,比创建对象要早。

2)销毁:可以利用元素的destroy-method="方法名"属性执行销毁方法。

指定的销毁方法是在容器关闭时触发,而且只适用于singleton模式的组件(只能为单例模式)。见2.6案例中step3、step4、step6。

2.6案例:Spring框架的使用以及2.1节-2.5节整合测试

step1:导入Spring开发包:spring.jar、commons-logging.jar和配置文件:applicationContext.xml

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:jee="http://www.springframework.org/schema/jee"

xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

Java

public void delete();public void save();

public JdbcCostDAO()

public void myinit()

public void mydestroy()

public void delete()

public void save()

step4:在applicationContext.xml配置文件中,将Bean组件(Java类)交给Spring容器

step5:在org.tarena.test包下,创建TestApplicationContext类,获取Spring容器对象,并测试

@Test

public void test1()

step6:在TestApplicationContext类中添加方法,测试销毁对象

@Test

/**关闭容器才会触发销毁,但关闭容器方法封装在AbstractApplicationContext类中 */

public void test2()

step7:在TestApplicationContext类中添加方法,测试单例

@Test

public void test3()

三、IoC

3.1 IoC概念

1)Inverse of Controller被称为控制反转或反向控制,其实真正体现的是“控制转移”。

2)所谓的控制指的是负责对象关系的指定、对象创建、初始化和销毁等逻辑。

3)IoC指的是将控制逻辑交给第三方框架或容器负责(即把Action中的控制逻辑提出来,交给第三方负责),当两个组件关系发生改变时,只需要修改框架或容器的配置即可。

4)IoC主要解决的是两个组件对象调用问题,可以以低耦合方式建立使用关系。

3.2 DI概念

1)Dependency Injection依赖注入。

2)Spring框架采用DI技术实现了IoC控制思想。

3)Spring提供了两种形式的注入方法:

setter方式注入(常用):依靠set方法,将组件对象传入(可注入多个对象)。

A.首先添加属性变量和set方法。

B.在该组件的定义中采用下面的描述方式:

u 注意事项:例如CostAction中有costDAO属性,而它的标准set方法名为setCostDAO,那么配置文件中的name就应该写costDAO(去掉set,首字母小写)。如果set方法名为setCost,那么name就应该写cost(去掉set,首字母小写)!确切的说,name不是看定义的属性名,而是set方法名。

构造方式注入(用的少):依靠构造方法,将组件对象传入。

A.在需要注入的组件中,添加带参数的构造方法。

B.在该组件的定义中,使用下面格式描述:

Java

3.3案例:测试IoC(set注入)

private CostDAO costDAO;//利用Spring的IOC机制使用CostDAO组件对象,set注入

public void setCostDAO(CostDAO costDAO) { this.costDAO = costDAO; }

public String execute()

step2:在applicationContext.xml配置文件中,将CostAction组件交给Spring容器

@Test//测试set注入

public void test1()

step4:测试结果为:

创建CostDAO对象初始化CostDAO对象 处理资费添加操作

利用JDBC技术实现保存资费记录。

3.4案例:测试IoC(构造注入)

private CostDAO costDAO;

public DeleteAction(CostDAO costDAO)//构造注入

costDAO.delete();//调用CostDAO中的delete方法 return "success";}

step2:在applicationContext.xml配置文件中,将DeleteAction组件交给Spring容器

step3:在TestIoc类中添加方法,测试构造注入

@Test//测试构造注入

public void test2()

step4:测试结果为:

创建CostDAO对象初始化CostDAO对象 处理资费删除操作

利用JDBC技术实现删除资费记录。

3.5案例:不用JDBC访问数据库,而是采用Hibernate访问

接3.3案例,如果不用JDBC访问数据库,而是采用Hibernate访问,则替换组件过程为:

step1:创建HibernateCostDAO类,并实现CostDAO接口

public void delete()

step2:在applicationContext.xml配置文件中,将HibernateCostDAO组件交给Spring容器

step3:修改3.3案例中step2中CostAction组件的描述

step4:再次执行3.3案例step3中test1方法,测试结果为:

处理资费添加操作 利用Hibernate技术实现保存资费记录

Java

四、

Spring中各种类型的数据注入

Spring可以为对象注入以下类型的数据。

4.1 Bean对象注入

4.2基本数据的注入

1)字符串、数字

4.3集合的注入

1)List、Set

集合中的值1集合中的值2…………

2)Map

…………

3)Properties

值1

值2…………

4)特殊用法:set方法接收字符串,内部进行处理(如分割),再存入集合属性

4.4案例:各类数据注入

step1:对象注入参考3.3、3.4案例

step2:创建MessageBean类,并定义不同类型的数据以及对应的set方法

private String username;//用户名private String fileDir;//上传路径

private List hbms;private Set cities;

private Map books;private Properties props;

private Set types;//允许上传类型

/** 注意set方法的名字!不是看属性名,而是看set方法名去掉set,首字母大写的名 */

public void setName(String username) //手动更改过名字

public void setDir(String fileDir) //手动更改过名字

……其他属性名字没改,其他属性代码略

public void setTypes(String str) {//特殊用法:注入一个字符串,分析之后给set集合赋值

String[] arr=str.split(",");types=new HashSet();

for(String s:arr)}

public void show(){

for(String s:hbms)

for(String c:cities)

Set> ens=books.entrySet();

Set keys=props.keySet();//另一种方式遍历

for(Object key:keys)

System.out.println("--允许上传类型如下--");//特殊用法

step3:applicationContext.xml配置文件中

/org/tarena/entity/Cost.hbm.xml

/org/tarena/entity/Admin.hbm.xml

北京上海

true

Java

step4:创建TestInjection类用于测试各类数据的注入

@Test

public void test1(){

String conf="/applicationContext.xml";

ApplicationContext ac=new ClassPathXmlApplicationContext(conf);

MessageBean bean=(MessageBean)ac.getBean("messageBean");

bean.show();}

五、

AOP概念

5.1什么是AOP

Aspect Oriented Programming,被称为面向方面编程。对单个对象(一对一)的解耦用IOC,而当有个共通组件,它对应多个其他组件(一对多),则解耦用AOP。如,拦截器。这也是为何在程序中大量的用IoC,而AOP却用的很少,因为程序中不可能有很多的共通部分。

5.2 AOP和OOP的区别

OOP是面向对象编程,AOP是以OOP为基础的。

OOP主要关注的是对象,如何抽象和封装对象。

AOP主要关注的是方面,方面组件可以以低耦合的方式切入到(作用到)其他某一批目标对象方法中(类似于Struts2中的拦截器)。

AOP主要解决共通处理和目标组件之间解耦。

5.3 AOP相关术语

1)方面(Aspect):指的是封装了共通处理的功能组件。该组件可以作用到某一批目标组件的方法上。

2)连接点(JoinPoint):指的是方面组件和具体的哪一个目标组件的方法有关系。

3)切入点(Pointcut):用于指定目标组件的表达式。指的是方面组件和哪一批目标组件方法有关系。多个连接点组成的集合就是切入点。如:a、b为切入点,1、2为连接点。

4)通知(Advice):用于指定方面组件和目标组件方法之间的作用时机。例如:先执行方面组件再执行目标方法;或先执行目标方法再执行方面组件。

5)目标(Target):利用切入点指定的组件和方法。

6)动态代理(AutoProxy):Spring同样采用了动态代理技术实现了AOP机制。当使用AOP之后,从容器getBean()获取的目标组件,返回的是一个动态生成的代理类。然后通过代理类执行业务方法,代理类负责调用方面组件功能和原目标组件功能。

Spring提供了下面两种动态代理技术实现:

1)采用CGLIB技术实现(目标组件没有接口采用此方法)

例如:public class 代理类 extends 原目标类型 { }

CostAction action=new 代理类();//代理类中有原来类的方法

2)采用JDK Proxy API实现(目标组件有接口采用此方法,即实现了某个接口)

例如:Public class 代理类 implements 原目标接口 { }

CostDAO costDAO=new 代理类();//代理类去实现了原目标接口,所以没有原来类的方法

5.4案例:AOP的使用,模拟某些组件需要记录日志的功能

接3.3、3.4案例,想让所有的操作进行日志记录,那么按以前的方式就需要给所有Action或DAO中添加记录日志的代码,如果Action或DAO很多,那么不便于维护。而使用AOP机制,则可以很方便的实现上述功能:

step1:导入AOP需要的包:aopalliance.jar、aspectjrt.jar、aspectjweaver.jar、cglib-nodep-2.1_3.jar

public void logger()

step3:在applicationContext.xml配置文件中,添加AOP机制

Java

step4:执行3.3案例step3,则发现添加操作已有了记录日志功能

创建CostDAO对象初始化CostDAO对象 记录了用户的操作日志

处理资费添加操作利用JDBC技术实现保存资费记录

step5:执行3.4案例step3,则发现删除操作已有了记录日志功能,记得加无参构造方法!

记录了用户的操作日志处理资费删除操作

利用Hibernate技术实现删除资费记录

u 注意事项:DeleteAction用的是构造注入,所以此处要把无参构造器再加上!因为AOP底层调用了DeleteAction的无参构造方法。不加则报错:Superclass has no null constructors but no arguments were given

5.5通知类型

通知决定方面组件和目标组件作用的关系。主要有以下几种类型通知:

1)前置通知:方面组件在目标方法之前执行。

2)后置通知:方面组件在目标方法之后执行,目标方法没有抛出异常才执行方面组件。

3)最终通知:方面组件在目标方法之后执行,目标方法有没有异常都会执行方面组件。

4)异常通知:方面组件在目标方法抛出异常后才执行。

5)环绕通知:方面组件在目标方法之前和之后执行。

try{ //前置通知执行时机

//执行目标方法

//后置通知执行时机

}catch(Exception e){//异常通知执行时机

}finally{//最终通知执行时机

}//环绕通知等价于前置+后置

5.6切入点

切入点用于指定目标组件和方法,Spring提供了多种表达式写法:

1)方法限定表达式:指定哪些方法启用方面组件。

形式:execution(修饰符? 返回类型 方法名(参数列表) throws 异常?)

示例:

execution(public * * (..)),匹配容器中,所有修饰符是public(不写则是无要求的),返回类型、方法名都没要求,参数列表也不要求的方法。

execution(* set*(..)),匹配容器中,方法以set开头的所有方法。

execution(* org.tarena.CostDAO.*(..)),匹配CostDAO类中的所有方法。

2)类型限定表达式:指定哪些类型的组件的所有方法启用方面组件(默认就是所有方法都启用,且知道类型,不到方法)。

形式:within(类型)示例:

3)Bean名称限定:按元素的id值进行匹配。

形式:Bean(id值)示例:

bean(costDAO),匹配id=costDAO的bean对象。

bean(*DAO),匹配所有id值以DAO结尾的bean对象。

4)args参数限定表达式:按方法参数类型限定匹配。

形式:args(类型)示例:

args(java.io.Serializable),匹配方法只有一个参数,并且类型符合Serializable的方法,public void f1(String s)、public void f2(int i)都能匹配。

u 注意事项:上述表达式可以使用&&、| | 运算符连接使用。

5.7案例:环绕通知,修改5.4案例使之动态显示所执行的操作

step1:新建opt.properties文件,自定义格式:包名.类名.方法名=操作名。在高版本MyEclipse中,切换到Properties界面,点击Add直接输入键和值,则中文会自动转为ASCII码。低版本的则需要使用JDK自带的转换工具:native2ascii.exe

#第一个为资费添加,第二个为资费删除

step2:新建PropertiesUtil工具类,用于解析.properties文件

private static Properties props = new Properties();

staticcatch(Exception ex)}

public static String getValue(String key){

String value = props.getProperty(key);

if(value == null)else}

step3:使用环绕通知,将5.4案例step3中的标签换为

step4:修改5.4案例step2中的LoggerBean类

public Object logger(ProceedingJoinPoint pjp) throws Throwable{//采用环绕通知,加参数

//前置逻辑

String className=pjp.getTarget().getClass().getName();//获取要执行的目标组件类名

String methodName=pjp.getSignature().getName();//获取要执行的方法名

//根据类名和方法名,给用户提示具体操作信息

//解析opt.properties,根据key获取value

String value=PropertiesUtil.getValue(key);

//XXX用户名可以通过ActionContext.getSession获取

new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(

new Date(System.currentTimeMillis())));

Object obj=pjp.proceed();//执行目标方法

//后置逻辑

return obj;}

step5:分别执行3.3案例step3和3.4案例step3,执行结果动态显示所执行的操作及时间

XXX执行了资费添加操作!操作时间:2013-08-19 20:14:47

XXX执行了资费删除操作!操作时间:2013-08-19 20:15:45

5.8案例:利用AOP实现异常处理,将异常信息写入文件

1)分析:方面:将异常写入文件。切入点:作用到所有Action业务方法上

public class ExceptionBean {//模拟,将异常信息写入文件

public void exec(Exception ex){//ex代表目标方法抛出的异常

System.out.println("将异常记录文件"+ex);//记录异常信息}}

step2:在applicationContext.xml配置文件中进行配置

step3:在DeleteAction的execute方法中添加异常

String str=null;str.length();

step4:执行3.3案例step3则添加操作执行正常;执行3.4案例step3则删除操作报空指针异常!显示结果:将异常记录文件java.lang.NullPointerException

Java

六、Log4j日志记录工具

6.1 Log4j介绍

Log4j主要用于日志信息的输出。可以将信息分级别(错误、严重、警告、调式信息)按不同方式(控制台、文件、数据库)和格式输出。

Log4j主要有以下3部分组件构成:

1)日志器(Logger):负责消息输出,提供了各种不同级别的输出方法。

2)输出器(Appender):负责控制消息输出的方式,例如输出到控制台、文件输出等。

3)布局器(格式器,Layout):负责控制消息的输出格式。

6.2 Log4j的使用

step1:引入log4j.jar

step2:在src下添加log4j.properties(定义了消息输出级别、采用哪种输出器、采用哪种布局器)

#level:大小写都可,myconsole是自己随便起的appender名字,可以写多个appender

log4j.rootLogger=debug,myconsole,myfile

#appender:可在org.apache.log4j中找自带的类

log4j.appender.myconsole=org.apache.log4j.ConsoleAppender

log4j.appender.myfile=org.apache.log4j.FileAppender

#log4j.appender.myfile.File=D:\error.txt

log4j.appender.myfile.File=D:\error.html

log4j.appender.myconsole.layout=org.apache.log4j.SimpleLayout

log4j.appender.myfile.layout=org.apache.log4j.HTMLLayout

u 注意事项:级别从小到大为:debug、info、warn、error、fatal

step3:创建TestLog4j类,测试利用日志器不同的方法输出消息。

public class TestLog4j {

public static Logger logger=Logger.getLogger(TestLog4j.class);

public static void main(String[] args) {

//能显示就显示,不显示也不会影响主程序后面的运行,仅是个辅助工具

logger.debug("调试信息");logger.info("普通信息");

logger.warn("警告信息");logger.error("错误信息");

logger.fatal("致命信息");}}

u 注意事项:

v 若在log4j.properties中指定的级别为debug,则五种信息都会显示;若指定的级别为error,则只显示error和fatal信息。

6.3案例:修改5.8案例,使用Log4j记录日志

step1:继续使用6.2节step1和step2

step2:修改5.8案例step1

public class ExceptionBean {//将异常信息写入文件

Logger logger=Logger.getLogger(Exception.class);

public void exec(Exception ex){//ex代表目标方法抛出的异常

logger.error("====异常信息====");//记录异常信息

logger.error("异常类型"+ex);

StackTraceElement[] els=ex.getStackTrace();

for(StackTraceElement el:els)}}

step3:执行3.4案例step3则删除操作报空指针异常(前提:已进行了5.8案例step3操作)!由于log4j.properties配置了两种输出方式,所以两种方式都有效。

控制台的显示结果:

XXX执行了资费删除操作!操作时间:2013-08-20 12:47:54

ERROR - ====异常信息====

ERROR - 异常类型java.lang.NullPointerException

……………………

HTML显示结果:

Java

Java学习资料获取(复制下段连接至浏览器即可)

data:text/html;charset=UTF-8;base64,5p625p6E5biI5a2m5Lmg6LWE5paZ5YWN6LS56aKG5Y+W6K+35Yqg5omj5omj5Y+35pivMTAxODkyNTc4MA==

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180122A079II00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券