您的位置:首页 > 编程语言 > Java开发

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

2018-01-12 11:11 483 查看
目 录

一、 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。

<bean id="标识符" class="Bean组件类型"></bean>

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模式,可以通过<bean>的scope属性修改为prototype模式。以后在Web程序中,通过扩展可以使用request、session等值。见2.6案例中step4、step7。

例如:<bean id="标识符" scope="prototype" class="Bean组件类型"></bean>

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

2.4 Bean对象创建的时机

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

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

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

例如:<bean id="标识符" scope="singleton" lazy-init="true" class="Bean组件类型"></bean>

<beans ...... default-lazy-init="false"></beans>

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

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

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

u 注意事项:

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

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

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

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

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

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

<?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: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">

</beans>



Java
step2:在org.tarena.dao包下,创建接口CostDAO,添加两个方法

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

step3:在org.tarena.dao包下,创建JdbcCostDAO类,并实现CostDAO接口

public JdbcCostDAO(){System.out.println("创建CostDAO对象");}

public void myinit(){System.out.println("初始化CostDAO对象");}

public void mydestroy(){System.out.println("销毁CostDAO对象");}

public void delete() {System.out.println("利用JDBC技术实现删除资费记录");}

public void save() {System.out.println("利用JDBC技术实现保存资费记录");}

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

<bean id="jdbcCostDAO" scope="singleton" lazy-init="true" init-method="myinit"

destroy-method="mydestroy"class="org.tarena.dao.JdbcCostDAO">

</bean>

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

@Test

public void test1(){String conf="/applicationContext.xml";

ApplicationContext ac=new ClassPathXmlApplicationContext(conf);//实例化容器

CostDAO costDAO=(CostDAO)ac.getBean("jdbcCostDAO");//获取Bean对象

costDAO.save();costDAO.delete();}

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

@Test

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

public void test2(){String conf="/applicationContext.xml";

ApplicationContext ac=new ClassPathXmlApplicationContext(conf);

AbstractApplicationContext ac=new ClassPathXmlApplicationContext(conf);

CostDAO costDAO=(CostDAO)ac.getBean("jdbcCostDAO");ac.close();}

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

@Test

public void test3(){String conf="/applicationContext.xml";

ApplicationContext ac=new ClassPathXmlApplicationContext(conf);

CostDAO costDAO1=(CostDAO)ac.getBean("jdbcCostDAO");

CostDAO costDAO2=(CostDAO)ac.getBean("jdbcCostDAO");

System.out.println(costDAO1==costDA
105da
O2);//true,所以Spring默认为单例模式}

三、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.在该组件的<bean>定义中采用下面的描述方式:

<property name="属性名" ref="要注入的Bean对象的id值"></property>

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

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

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

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

<constructor-arg index="参数索引" ref="要注入的Bean对象的id值"></constructor-arg>



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

step1:接2.6案例,在org.tarena.action包下,创建CostAction类,调用save方法

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

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

public String execute(){System.out.println("处理资费添加操作");

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

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

<bean id="costAction" scope="prototype" class="org.tarena.action.CostAction">

<!-- 利用setCostDAO方法接收jdbcCostDAO对象 -->

<property name="costDAO" ref="jdbcCostDAO"></property>

<!-- name:与CostAction中对应的set方法匹配的名。ref:指明哪个对象 -->

</bean><!--此处用到了2.6案例中step3描述的组件JdbcCostDAo-->

step3:在org.tarena.test包下,创建TestIoc类,用于测试IOC机制

@Test//测试set注入

public void test1(){String conf="/applicationContext.xml";

ApplicationContext ac=new ClassPathXmlApplicationContext(conf);

CostAction action=(CostAction)ac.getBean("costAction");//获得CostAction类的对象

action.execute();}

step4:测试结果为:

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

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

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

step1:接3.3案例,在org.tarena.action包下,创建DeleteAction类,调用delete方法

private CostDAO costDAO;

public DeleteAction(CostDAO costDAO){this.costDAO=costDAO; }//构造注入

public String execute() { System.out.println("处理资费删除操作");

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

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

<bean id="deleteAction" scope="prototype"class="org.tarena.action.DeleteAction">

<!-- 索引0:给构造方法中第一个参数注入一个jdbcCostDAO对象。

若多个参数则重复追加constructor-arg元素即可 -->

<constructor-arg index="0" ref="jdbcCostDAO"></constructor-arg><!-- 构造注入 -->

</bean>

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

@Test//测试构造注入

public void test2(){String conf="/applicationContext.xml";

ApplicationContext ac=new ClassPathXmlApplicationContext(conf);

DeleteAction action=(DeleteAction)ac.getBean("deleteAction");

action.execute();}

step4:测试结果为:

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

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

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

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

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

public void delete() {System.out.println("利用Hibernate技术实现删除资费记录");}

public void save() { System.out.println("利用Hibernate技术实现保存资费记录");}

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

<bean id="hibernateCostDAO" class="org.tarena.dao.HibernateCostDAO"></bean>

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

<bean id="costAction" scope="prototype" class="org.tarena.action.CostAction">

<!-- 修改ref属性的指引 -->

<property name="costDAO" ref="hibernateCostDAO"></property>

<!-- name:与CostAction中添加的属性名相同。ref:指明哪个对象 -->

</bean>

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

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



Java
四、

Spring中各种类型的数据注入

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

4.1 Bean对象注入

<property name="属性名" ref="要注入的Bean对象的id值"></property>

4.2基本数据的注入

1)字符串、数字

<property name="属性名" value="要注入的值"></property>

4.3集合的注入

1)List、Set

<property name="集合属性名">

<list><!-- 普通值用<value>标签,对象用<bean>标签 -->

<value>集合中的值1</value><value>集合中的值2</value>…………

</list>

</property>

2)Map

<property name="集合属性名">

<map><!-- 普通值用<value>标签,对象用<bean>标签 -->

<entry key="键1" value="值1"></entry>

<entry key="键2" value="值2"></entry> …………

</map>

</property>

3)Properties

<property name="集合属性名">

<props>

<prop key="键1">值1</prop>

<prop key="键2">值2</prop>…………

</props>

</property>

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

<property name="集合属性名" value="字符串"></property>

4.4案例:各类数据注入

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

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

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

private List<String> hbms;private Set<String> cities;

private Map<Integer, String> books;private Properties props;

private Set<String> types;//允许上传类型

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

public void setName(String username) {this.username = username;}//手动更改过名字

public void setDir(String fileDir) {this.fileDir = fileDir;}//手动更改过名字

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

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

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

for(String s:arr){types.add(s);}}

public void show(){

System.out.println("用户名:"+username);System.out.println("上传路径:"+fileDir);

System.out.println("--hbms文件如下--");

for(String s:hbms){System.out.println(s);}

System.out.println("--city城市如下--");

for(String c:cities){System.out.println(c);}

System.out.println("--book图书信息--");

Set<Entry<Integer,String>> ens=books.entrySet();

for(Entry en:ens){ System.out.println(en.getKey()+" "+en.getValue()); }

System.out.println("--props参数如下--");

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

for(Object key:keys){System.out.println(key+" "+

props.getProperty(key.toString()));}

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

for(String type:types){ System.out.println(type);}}

step3:applicationContext.xml配置文件中

<!-- 各种数据类型的注入 -->

<bean id="messageBean" class="org.tarena.dao.MessageBean">

<!-- 注意名字 name指的是set方法名去掉set,首字母大写的名,不看属性名! -->

<property name="name" value="root"></property><!--手动更改过set方法名 -->

<property name="dir" value="D:\images"></property><!--手动更改过set方法名 -->

<property name="hbms">

<list><value>/org/tarena/entity/Cost.hbm.xml</value>

<value>/org/tarena/entity/Admin.hbm.xml</value></list></property>

<property name="cities">

<set><value>北京</value><value>上海</value></set></property>

<property name="books">

<map><entry key="1" value="Java语言基础"></entry>

<entry key="2" value="Java Web入门"></entry></map></property>

<property name="props">

<props><prop key="hibernate.show_sql">true</prop>

<prop key="hibernate.dialect_sql">org.hibernate.dialect.OracleDialect</prop>

</props>

</property>

<!-- 特殊用法,set方法传入字符串,内部进行处理,再存入集合 -->

<property name="types" value="jpg,gif,jpeg"></property>

</bean>



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

step2:在org.tarena.aop包下新建LoggerBean类,并添加logger方法用于模拟记录日志功能

public void logger(){System.out.println("记录了用户的操作日志");}

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

<bean id="loggerBean" class="org.tarena.aop.LoggerBean"></bean>

<aop:config>

<!--定义切入点,指定目标组件和方法。id:可任意起个名字。expression:指定哪些组件是目标,并作用在这些目标的方法上。下面表示所有Action中的所有方法为切入点-->

<aop:pointcut id="actionPointcut" expression="within(org.tarena.action.*)" />

<!--定义方面,将loggerBean对象指定为方面组件,loggerBean从普通Bean组件升级为了方面组件-->

<aop:aspect id="loggerAspect" ref="loggerBean">

<!-- aop:before在操作前执行 aop:after操作后执行 -->

<!-- 定义通知,aop:before:指定先执行方面组件的logger方法,再执行切入点指定的目标方法。aop:after:与aop:before相反 -->

<aop:before pointcut-ref="actionPointcut" method="logger"/>

</aop:aspect>

</aop:config>



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{ //前置通知执行时机<aop:before>

//执行目标方法

//后置通知执行时机<aop:after-returning>

}catch(Exception e){//异常通知执行时机<aop:after-throwing>

}finally{//最终通知执行时机<aop:after>

}//环绕通知等价于前置+后置<aop:around>

5.6切入点

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

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

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

②示例:

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

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

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

execution(* org.tarena.dao.*.*(..)),匹配dao包下所有类所有方法。

execution(* org.tarena.dao..*.*(..)),匹配dao包及其子包中所有类所有方法。

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

①形式:within(类型)②示例:

within(com.xyz.service.*),匹配service包下的所有类所有方法

within(com.xyz.service..*),匹配service包及其子包中的所有类所有方法

within(org.tarena.dao.CostDAO),匹配CostDAO所有方法

u 注意事项:within(com.xyz.service..*.*),为错误的,就到方法名!

3)Bean名称限定:按<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

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

org.tarena.action.CostAction.execute=资费添加

org.tarena.action.DeleteAction=资费删除

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

private static Properties props = new Properties();

static{try{props.load(PropertiesUtil.class.getClassLoader()

.getResourceAsStream("opt.properties"));

}catch(Exception ex){ex.printStackTrace();}}

public static String getValue(String key){

String value = props.getProperty(key);

if(value == null){return ""; }else{return value; }}

step3:使用环绕通知,将5.4案例step3中的<aop:before />标签换为<aop:around />

<aop:around pointcut-ref="actionPointcut" method="logger"/>

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

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

//前置逻辑

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

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

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

String key=className+"."+methodName;System.out.println(key);

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

String value=PropertiesUtil.getValue(key);

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

System.out.println("XXX执行了"+value+"操作!操作时间:"+

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业务方法上

within(org.tarena.action..*)。通知:异常通知<aop:after-throwing>。

2)实现:step1:在org.tarena.aop包中创建ExceptionBean类

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

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

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

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

<bean id="exceptionBean" class="org.tarena.aop.ExceptionBean"></bean>

<aop:pointcut id="actionPointcut" expression="within(org.tarena.action.*)"/>

<!-- 定义方面组件,将exceptionBean指定为方面 -->

<aop:aspect id="exceptionAspect" ref="exceptionBean">

<!-- throwing:和自定的方法中的参数名相同。一定要把异常抛出来才行!

try-catch了则不行! -->

<aop:after-throwing pointcut-ref="actionPointcut" method="exec" throwing="ex"/>

</aop:aspect>

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

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

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 导包为org.apache.log4j.Logger。

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){logger.error(el);}}}

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

控制台的显示结果:

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

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

ERROR - 异常类型java.lang.NullPointerException

……………………

HTML显示结果:



Java

以上所述是小编给大家介绍的Spring Boot 模块组成,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的!

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

data:textml;charset=UTF-8;base64,5oGt5Zac5L2g77yM5p625p6E5biI5a2m5Lmg576k5Y+35pivNjg2NTc5MDE0Cg==
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息