05 Spring的AOP
- 格式:pdf
- 大小:514.41 KB
- 文档页数:51
SpringBoot使⽤过滤器、拦截器、切⾯(AOP),及其之间的区别和执⾏顺序先上代码,下⾯的demo中包含多个拦截器、过滤器,以及切⾯的前置通知/后置通知/环绕通知:下⾯总结⼀下相关原理:⾸先了解⼀下SpringMVC的执⾏流程具体流程如下1. ⽤户发起请求到前端控制器(Controller)2. 前端控制器没有处理业务逻辑的能⼒,需要找到具体的模型对象处理(Handler),到处理器映射器(HandlerMapping)中查找Handler对象(Model)。
3. HandlerMapping返回执⾏链,包含了2部分内容:① Handler对象、②拦截器数组4. 前端处理器通过处理器适配器包装后执⾏Handler对象。
5. 处理业务逻辑。
6. Handler处理完业务逻辑,返回ModelAndView对象,其中view是视图名称,不是真正的视图对象。
7. 将ModelAndView返回给前端控制器。
8. 视图解析器(ViewResolver)返回真正的视图对象(View)。
9. (此时前端控制器中既有视图⼜有Model对象数据)前端控制器根据模型数据和视图对象,进⾏视图渲染。
10. 返回渲染后的视图(html/json/xml)返回。
11. 给⽤户产⽣响应。
核⼼就是DispatcherServlet核⼼控制器,我们看源码可知道DispatcherServlet是Servlet的⼦类下⾯⽤⼀张图说⼀下过滤器、Servlet容器、拦截器、AOP、Controller之间的关系然后具体执⾏流程如下:拦截器和过滤器的区别1、拦截器不依赖与servlet容器是SpringMVC⾃带的,过滤器依赖于Servlet容器。
2、拦截器是基于java的反射机制的,⽽过滤器是基于函数回调。
3、拦截器只能对action请求起作⽤,⽽过滤器则可以对⼏乎所有的请求起作⽤。
4、拦截器可以访问controller上下⽂、值栈⾥的对象,⽽过滤器不能访问。
Spring的AOP配置(2011-04-01 20:38:58)转载标签:分类:SSH框架springaop配置获取参数it1.先写一个普通类:package com.spring.aop;public class Common {public void execute(String username,String password){ System.out.println("------------------普通类----------------");}}2.写一个切面类,用于合法性校验和日志添加:package com.spring.aop;public class Check {public void checkValidity(){System.out.println("------------------验证合法性----------------"); }public void addLog(JoinPoint j){System.out.println("------------------添加日志----------------");Object obj[] = j.getArgs();for(Object o :obj){System.out.println(o);}System.out.println("========checkSecurity=="+j.getSignature().getName());//这个是获得方法名}}3.配置AOP,使用XML方式:(注意红色标志的内容)<?xml version="1.0" encoding="UTF-8"?><beansxmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans-2.5.xsd/schema/aop/schema/aop/spring-aop-2.5.xsd"><bean id="common" class="mon"/><bean id="check" class="com.spring.aop.Check"/><aop:config><aop:aspect id="myAop" ref="check"><aop:pointcut id="target" expression="execution(*mon.execute(..))"/><aop:before method="checkValidity" pointcut-ref="target"/><aop:after method="addLog" pointcut-ref="target"/></aop:aspect></aop:config>注意:execution(* com.spring.aop.*.*(..))"/这样写应该就可以了这是com.aptech.jb.epet.dao.hibimpl 包下所有的类的所有方法。
springaop配置切点执⾏了两次的原因
如果切点执⾏了两次,猜想原因:
1、可能是我配置的是被切对象中的所有⽅法,⽽我当时执⾏的那个⽅法恰好执⾏了是会执⾏切点⽅法中的两个⽅法;
<bean id="orderTrackingManager" class="com.sdk.manager.order.OrderTrackingManagerImpl"/>
<aop:config>
<aop:aspect id="orderTrackingAspect" ref="orderTrackingManager">
<aop:pointcut id="saveTrackOrderLogMethod" expression="execution(* com.sdk.manager.order.OrderManager.*(*,*))"/>
<aop:after-returning method="saveTrackOrderLog" pointcut-ref="saveTrackOrderLogMethod"/>
</aop:aspect>
</aop:config>
</beans>
2、经过各⽅度娘,是代理执⾏了两次,即配置了多个代理创建器,多个代理创建器,产⽣了多个代理,代理2代理了代理1,代理1代理了本体,所以就产⽣了aop执⾏两次查看测试类的头⽂件发现:
配置aop的⽂件被引⽤了两次。
Spring:AOP(xml形式的环绕通知)AOP概念:AOP的作⽤以及优势AOP的相关术语基于XML的AOP配置<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/aop/schema/aop/spring-aop.xsd">View Codespring中基于XML的AOP配置步骤 1、把通知Bean也交给spring来管理 2、使⽤aop:config标签表明开始AOP的配置 3、使⽤aop:aspect标签表明配置切⾯ id属性:是给切⾯提供⼀个唯⼀标识 ref属性:是指定通知类bean的Id。
4、在aop:aspect标签的内部使⽤对应标签来配置通知的类型 我们现在⽰例是让printLog⽅法在切⼊点⽅法执⾏之前之前:所以是前置通知 aop:before:表⽰配置前置通知 method属性:⽤于指定Logger类中哪个⽅法是前置通知 pointcut属性:⽤于指定切⼊点表达式,该表达式的含义指的是对业务层中哪些⽅法增强切⼊点表达式的写法:关键字:execution(表达式)表达式:访问修饰符返回值包名.包名.包名...类名.⽅法名(参数列表)标准的表达式写法:public void com.itheima.service.impl.AccountServiceImpl.saveAccount()访问修饰符可以省略void com.itheima.service.impl.AccountServiceImpl.saveAccount()返回值可以使⽤通配符,表⽰任意返回值* com.itheima.service.impl.AccountServiceImpl.saveAccount()包名可以使⽤通配符,表⽰任意包。
SpringAOP的原理和应用场景SpringAOP(Aspect-Oriented Programming)是Spring框架中的一个重要组成部分,它提供了一种通过预定义的方式,将横切关注点(Cross-cutting Concerns)与业务逻辑进行解耦的机制。
本文将介绍SpringAOP的原理及其在实际应用场景中的应用。
一、SpringAOP的原理SpringAOP基于代理模式(Proxy Pattern)实现。
在SpringAOP中,通过生成与原始类(被代理类)具有相同接口的代理类,将横切逻辑编织到业务逻辑中。
在运行时,当调用代理类的方法时,会在方法执行前、后或异常抛出时插入相应的横切逻辑代码。
具体而言,SpringAOP使用了以下几个核心概念:1. 切面(Aspect):切面是横切逻辑的模块化单元,它包含了一组通知(Advice)和切点(Pointcut)。
2. 通知(Advice):通知定义了实际的横切逻辑代码,并规定了何时执行该代码。
SpringAOP提供了五种类型的通知:前置通知(Before)、后置通知(After)、返回通知(After-returning)、异常通知(After-throwing)和环绕通知(Around)。
3. 切点(Pointcut):切点指定了在哪些连接点(Join Point)上执行通知。
连接点可以是方法调用、属性访问等程序执行的点。
4. 连接点(Join Point):连接点是程序执行过程中的一个特定点,如方法调用前、方法调用后等。
通知通过切点来选择连接点。
5. 织入(Weaving):织入是将切面应用到目标对象,并创建代理对象的过程。
织入可以在编译时、类加载时或运行时进行。
二、SpringAOP的应用场景SpringAOP可应用于各种场景,用于解决跨越多个模块或类的横切关注点问题。
以下是一些常见的SpringAOP应用场景:1. 日志记录:通过在关键方法的前后插入日志代码,实现对系统运行状态的监控和记录。
SpringAOP⽰例与实现原理总结——传统springaop、基于切⾯注⼊、基于@Asp。
⼀、代码实践1)经典的Spring Aop经典的spring aop,是基于动态代理技术的。
实现⽅式上,最常⽤的是实现MethodInterceptor接⼝来提供环绕通知,创建若⼲代理,然后使⽤ProxyBeanFactory配置⼯⼚bean,⽣成拦截器链,完成拦截。
⽰例如下:1package demo.spring;23import org.aopalliance.intercept.MethodInterceptor;4import org.aopalliance.intercept.MethodInvocation;5import org.junit.Test;6import org.junit.runner.RunWith;7import org.springframework.beans.factory.annotation.Autowired;8import org.springframework.test.context.ContextConfiguration;9import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;1011 @RunWith(SpringJUnit4ClassRunner.class)12 @ContextConfiguration("classpath:spring-config.xml")13public class TraditionalSpringAopDemo {14 @Autowired15private Service proxy;1617 @Test18public void test() {19 proxy.execute("hello world!");20 }21 }2223interface Service {24void execute(String str);25 }2627class ServiceImpl implements Service {28 @Override29public void execute(String str) {30 System.out.println("execute invoke: " + str);31 }32 }3334class Interceptor1 implements MethodInterceptor {35 @Override36public Object invoke(MethodInvocation methodInvocation) throws Throwable {37 System.out.println("interceptor1,before invoke");38 Object ret = methodInvocation.proceed();39 System.out.println("interceptor1,after invoke");40return ret;41 }42 }4344class Interceptor2 implements MethodInterceptor {45 @Override46public Object invoke(MethodInvocation methodInvocation) throws Throwable {47 System.out.println("interceptor2,before invoke");48 Object ret = methodInvocation.proceed();49 System.out.println("interceptor2,after invoke");50return ret;51 }52 }xml⽂件配置:1<?xml version="1.0" encoding="UTF-8"?>2<beans xmlns="/schema/beans"3 xmlns:xsi="/2001/XMLSchema-instance"4 xmlns:context="/schema/context"5 xmlns:aop="/schema/aop"6 xsi:schemaLocation="/schema/beans /schema/beans/spring-beans.xsd /schema/context /schema/context/sprin 78<context:component-scan base-package="demo.spring"/>910<bean class="demo.spring.ServiceImpl" id="service"></bean>11<bean class="demo.spring.Interceptor1" id="interceptor1"></bean>12<bean class="demo.spring.Interceptor2" id="interceptor2"></bean>13<bean class="org.springframework.aop.framework.ProxyFactoryBean" id="proxy">14<property name="target" ref="service"/>15<property name="interceptorNames">16<list>17<value>interceptor1</value>18<value>interceptor2</value>19</list>20</property>21</bean>22</beans>结果:interceptor1,before invokeinterceptor2,before invokeexecute invoke: hello world!interceptor2,after invokeinterceptor1,after invoke可以看到拦截链的执⾏过程与拦截器顺序的关系。
⾯试之Spring框架IOC和AOP的实现原理本⽂讲的是⾯试之Spring框架IOC和AOP的实现原理, IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,⽽不是传统实现中,由程序代码直接操控。
控制权由应⽤代码中转到了外部容器,控制权的转移是所。
IoC(Inversion of Control)(1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,⽽不是传统实现中,由程序代码直接操控。
控制权由应⽤代码中转到了外部容器,控制权的转移是所谓反转。
对于Spring⽽⾔,就是由Spring来控制对象的⽣命周期和对象之间的关系;IoC还有另外⼀个名字——“依赖注⼊(Dependency Injection)”。
从名字上理解,所谓依赖注⼊,即组件之间的依赖关系由容器在运⾏期决定,即由容器动态地将某种依赖关系注⼊到组件之中。
(2). 在Spring的⼯作⽅式中,所有的类都会在spring容器中登记,告诉spring这是个什么东西,你需要什么东西,然后spring会在系统运⾏到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。
所有的类的创建、销毁都由 spring来控制,也就是说控制对象⽣存周期的不再是引⽤它的对象,⽽是spring。
对于某个具体的对象⽽⾔,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
(3). 在系统运⾏中,动态的向某个对象提供它所需要的其他对象。
(4). 依赖注⼊的思想是通过反射机制实现的,在实例化⼀个类时,它通过反射调⽤类中set⽅法将事先保存在HashMap中的类属性注⼊到类中。
总⽽⾔之,在传统的对象创建⽅式中,通常由调⽤者来创建被调⽤者的实例,⽽在Spring中创建被调⽤者的⼯作由Spring来完成,然后注⼊调⽤者,即所谓的依赖注⼊or控制反转。
spring中aop不⽣效的⼏种解决办法先看下这个问题的背景:假设有⼀个spring应⽤,开发⼈员希望⾃定义⼀个注解@Log,可以加到指定的⽅法上,实现⾃动记录⽇志(⼊参、出参、响应耗时这些)package blogs.yjmyzz.springbootdemo.aspect;import ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Log {}然后再写⼀个Aspect来解析这个注解,对打了Log注解的⽅法进⾏增强处理 package blogs.yjmyzz.springbootdemo.aspect;import ng.JoinPoint;import ng.ProceedingJoinPoint;import ng.annotation.Around;import ng.annotation.Aspect;import ng.annotation.Pointcut;import ponent;import ng.reflect.Method;@Component@Aspectpublic class LogAspect {@Pointcut("execution (* blogs.yjmyzz.springbootdemo.service..*.*(..))")public void logPointcut() {}@Around("logPointcut()")public void around(JoinPoint point) {String methodName = point.getSignature().getName();Object[] args = point.getArgs();Class<?>[] argTypes = new Class[point.getArgs().length];for (int i = 0; i < args.length; i++) {argTypes[i] = args[i].getClass();}Method method = null;try {method = point.getTarget().getClass().getMethod(methodName, argTypes);} catch (Exception e) {e.printStackTrace();}//获取⽅法上的注解Log log = method.getAnnotation(Log.class);if (log != null) {//演⽰⽅法执⾏前,记录⼀⾏⽇志System.out.println("before:" + methodName);}try {//执⾏⽅法((ProceedingJoinPoint) point).proceed();} catch (Throwable throwable) {throwable.printStackTrace();} finally {if (log != null) {//演⽰⽅法执⾏后,记录⼀⾏⽇志System.out.println("after:" + methodName);}}}}写⼀个测试Service类:package blogs.yjmyzz.springbootdemo.service;import blogs.yjmyzz.springbootdemo.aspect.Log;import ponent;@Componentpublic class HelloService {@Logpublic void sayHi(String msg) {System.out.println("\tsayHi:" + msg);}public void anotherSayHi(String msg) {this.sayHi(msg);}}最后来跑⼀把:package blogs.yjmyzz.springbootdemo;import blogs.yjmyzz.springbootdemo.service.HelloService;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import ponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** @author 菩提树下的杨过*/@ComponentScan("blogs.yjmyzz")@Configuration@EnableAspectJAutoProxypublic class SampleApplication {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SampleApplication.class);HelloService helloService = context.getBean(HelloService.class);helloService.sayHi("hi-1");System.out.println("\n");helloService.anotherSayHi("hi-2");}}输出如下:显然HelloService中的anotherSayHi⽅法,并未被aop增强。
Spring中IOC和AOP的深⼊讲解前⾔Spring是⼀个开源框架,Spring是于2003 年兴起的⼀个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍⽣⽽来。
它是为了解决企业应⽤开发的复杂性⽽创建的。
Spring使⽤基本的JavaBean来完成以前只可能由EJB完成的事情。
然⽽,Spring的⽤途不仅限于服务器端的开发。
从简单性、可测试性和松耦合的⾓度⽽⾔,任何Java应⽤都可以从Spring中受益。
简单来说,Spring是⼀个轻量级的控制反转(IoC)和⾯向切⾯(AOP)的容器框架。
这篇⽂章主要讲 Spring 中的⼏个点,Spring 中的 IOC,AOP,下⼀篇说说 Spring 中的事务操作,注解和 XML 配置。
Spring 简介Spring 是⼀个开源的轻量级的企业级框架,其核⼼是反转控制 (IoC) 和⾯向切⾯ (AOP) 的容器框架。
我们可以把 Spring 看成是对象的容器,容器中可以包含很多对象,所以 Spring 有很多强⼤的功能。
⼀句话,Spring 是项⽬中对象的管家,负责管理项⽬中⽤到的所有对象。
所以在项⽬三层架构中,Spring 不属于某⼀特定层。
Spring 的 Hello World想要构建⼀个 Spring 的⼊门程序,我们需要导⼊ 4 个核⼼包和 2 个辅助包,创建⼀个实体类,最主要的是编写核⼼配置⽂件,applicationContext.xml 放在 src 下。
最后写⼀个测试类即可。
此时在测试类中我们不需要在使⽤ new 关键字去创建对象了。
这也正是 Spring 的作⽤所在,会⾃动给我创建对象。
上图展⽰的就是最基本的演⽰,也是很容易就理解了,配置⽂件中配置了 user 对象,我们通过加载配置⽂件来获取对象从⽽避免了使⽤ new 来创建。
springAop后置通知AfterReturningAdvice实现原理和代码案例Spring AOP(Aspect-Oriented Programming)是一种面向切面编程的方式,通过在代码中定义切面、通知、切点等元素,可以实现对方法的增强,例如在方法执行之前、之后、抛出异常时等插入特定的代码逻辑。
其中,后置通知(After Returning Advice)是一种在被通知方法成功执行后执行的通知。
后置通知的实现原理是利用动态代理机制,通过代理对象来调用目标对象方法,从而实现对方法的增强。
Spring AOP提供了两种方式来实现后置通知:一种是使用基于配置的方式,另一种是使用基于注解的方式。
下面以基于注解的方式为例,介绍后置通知的实现原理和代码案例。
实现后置通知的步骤如下:1. 创建一个普通的Java类,作为目标对象,其中包含一个被通知的方法。
```javapublic class UserServicepublic void addUser(String username)System.out.println("Add user: " + username);}``````javapublic class LogAspectpublic void afterReturning(JoinPoint joinPoint, Object result)System.out.println("Method executed successfully: " + joinPoint.getSignature(.getName();}``````javapublic class AppConfigpublic UserService userServicreturn new UserService(;}public LogAspect logAspecreturn new LogAspect(;}``````javapublic class UserServiceTestprivate UserService userService;public void testAddUseuserService.addUser("testUser");}```5.运行测试类,控制台输出:```Add user: testUserMethod executed successfully: addUser```代码解析:- returning:定义一个Object类型的参数result,用于接收目标方法的返回值。
第5章 Spring的AOP在第4章中,笔者通过事件传递的机制实现了日志的输出,其实Spring的AOP在这方面提供了更强大的功能。
本章将首先让读者了解AOP的基本思想,然后通过对Java代理机制进行分析,引出AOP的3个关键概念,接着对Spring的AOP进行介绍,最后通过一个完整的实例让读者掌握Spring AOP的使用方法。
5.1 AOP基本思想AOP的意思是面向方面编程,英文全称是Aspect Oriented Programming,它使开发人员可以更好地将本不该彼此粘合在一起的功能分离开。
5.1.1 认识AOP开发人员在编写应用程序时,通常包含两种代码:一种是和业务系统有关的代码,一是和业务系统关系不大的代码,例如日志、权限、异常处理、事务处理等。
以前编写代码时,这两种代码基本是写在一起的,这样在程序中,到处充满着相同或类似的代码,例如日志信息的输出,每个方法都要写日志的输出,不利于程序的维护。
而AOP就是使这两种代码分离的思想。
使用AOP,就不用在业务逻辑中实现与业务功能关系不大的代码,从而降低了两种代码的耦合性,达到易于维护和重用的目的。
AOP,从字面的意思来理解就是面向方面编程,但却容易让初学者一头雾水,很多资料也都对AOP进行过解释,但过多地从理论的角度进行讲解其实用性,这里不再多讲,仅用一个例子来说明:基本上每个方法都要用日志进行记录,那么如果按照面向对象的思路来说,就是每个对象都有记录日志这样一个行为。
要在每个方法里添加日志的信息,必然会产生大量的重复代码,但可以将记录日志看作是一个横切面,所有对这些方法的调用都要经过这个横切面,然后在这个横切面进行记录日志的操作,这样就达到代码重用和易于维护的目的了,这就是AOP的思想。
5.1.2 AOP与OOP对比分析OOP(面向对象编程)对现代编程产生了深远的影响,经过多年的发展,目前已日趋成熟,它能很好地解决软件系统中角色划分的问题,借助于面向对象的分析、设计和实现,开发人员可以将现实领域的实体转换成软件系统中的对象,从而很自然地完成从现实到软第5章Spring的AOP ·75·件的转换。
但OOP并不是一种完美的思想,在某些方面,OOP也有其不足之处。
比如在日志、事务处理、权限管理等方面,当应用OOP将这些内容封装为对象的行为时,会产生大量的重复代码,虽然通过一些方法可以减少这种重复,但却不能彻底地解决该问题,于是AOP出现了。
前面讲过AOP能够降低代码的耦合性,使得代码易于维护和重用。
一个应用程序分为核心关注点和横切关注点。
核心关注点和具体应用的功能相关,而横切关注点存在于整个系统的范围内。
在AOP里,每个关注点的实现并不知道是否有其他关注点关注它,这是AOP和OOP 的主要区别。
在AOP里,组合的流向是从横切关注点到主关注点,而OOP中组合的流向则是从主关注点到横切关注点。
从这点可以看出AOP和OOP它们所关注的对象是不同的,所以AOP可以和OOP很好地共存,AOP是OOP的有益补充,而不是其对立面。
5.1.3 AOP与Java的代理机制AOP是一种思想,它和具体的实现技术无关。
任何一种符合AOP思想的技术实现,都可以看作是AOP的实现。
JDK 1.3以后,Java提供了动态代理的机制。
通过Java的动态代理机制,就可以很容易地实现AOP的思想。
实际上Spring的AOP也是建立在Java的代理机制之上的。
要理解Spring 的AOP,先来了解Java的代理机制。
下面主要通过一个输出日志的实例来使读者先了解Java 的代理机制,从而引出AOP的几个关键点。
5.2 从一个输出日志的实例分析Java的代理机制上面讲到,要了解Spring的AOP,先来了解Java的代理机制。
本节主要通过一个输出日志的实例来分析Java的代理机制。
首先介绍以前写日志的时候是怎么实现的,然后讲解使用Java的代理机制怎么实现日志的输出,接着讲解怎样通过Java的动态代理机制把这个日志输出改成通用的,最后引出AOP的几个关键点。
5.2.1 通用的日志输出方法在笔者使用Spring以前开发的程序中,不管是使用Java自动的日志工具,还是使用Log4j,或是自己编写的日志工具,都要在每一个业务逻辑方法里编写记录日志的代码。
使用AOP就可以使业务逻辑和记录日志这两件事情分离开。
这个输出日志实例的实现思路是:首先给出原来在程序中编写日志的方法,然后编写测试程序,查看输出结果,最后对这种方法进行总结,指出这种方法的缺点。
具体编写步骤如下:(1)打开Eclipse,在com.gc.action包中建立一个Java文件TimeBook.java,用来模拟实际业务中考勤审核的业务逻辑。
(2)原来在程序中编写日志时,都要在每一个业务逻辑方法里编写记录日志的代码。
Spring 从入门到精通·76·TimeBook.java 的示例代码如下: //******* TimeBook.java**************import org.apache.log4j.Level;import org.apache.log4j.Logger;public class TimeBook {private Logger logger = Logger.getLogger(this.getClass().getName());//审核数据的相关程序public void doAuditing(String name) {logger.log(, name + " 开始审核数据....");//审核数据的相关程序……logger.log(, name + " 审核数据结束....");}}代码说明:在业务逻辑中使用log4j 作为日志输出的工具。
doAuditing()方法用来处理实际业务中的考勤审核。
参数name ,用来传入是谁执行了类TimeBook 中的doAuditing()方法。
在审核代码的前后添加了用logger.log()方法实现日志输出的功能。
(3)编写测试程序,继续在以前的测试程序TestHelloWorld 的基础上进行修改,TestHelloWorld.java 的示例代码如下://******* TestHelloWorld.java**************package com.gc.test;import com.gc.action.TimeBook;public class TestHelloWorld {public static void main(String[] args) {TimeBook timeBook = new TimeBook();timeBook.doAuditing("张三");}}代码说明:timeBook.doAuditing("张三")表示该程序的执行人是“张三”。
(4)运行测试程序,查看通过TimeBook 类输出的日志信息,如图5.1所示。
图5.1 通过TimeBook 类输出日志信息在上面的示例中,笔者把日志信息添加在了具体的业务逻辑中,假如程序中其他的代码都需要日志输出的功能,那么每个程序就都要添加和上面类似的代码。
这样,在程序中,就会存在很多类似的日志输出代码,造成了很大的耦合,通过什么方法可以使业务逻辑和输出日志的代码分离呢?通过面向接口编程可以改进这个问题。
第5章Spring的AOP ·77·5.2.2 通过面向接口编程实现日志输出通过前面的示例程序,读者可以了解到以前添加日志信息方法的缺点。
下面主要通过面向接口编程来改进这个缺点。
其实现思路是:首先把执行考勤审核的doAuditing()方法提取出来成为接口,然后通过一个实体类来实现这个方法,在这个方法里编写具体的考勤审核的业务逻辑,接着通过一个代理类来进行日志输出,最后编写测试程序,查看输出结果。
具体步骤如下:(1)在com.gc.impl包中,建立一个接口TimeBookInterface。
TimeBookInterface.java 的示例代码如下://******* TimeBookInterface.java**************package com.gc.impl;import org.apache.log4j.Level;//通过面向接口编程实现日志输出public interface TimeBookInterface {public void doAuditing(String name);}(2)在com.gc.action包中,使前面已经建立好的类TimeBook实现接口TimeBookInterface,在doAuditing()方法中编写具体的考勤审核代码。
TimeBook.java的示例代码如下://******* TimeBook.java**************package com.gc.action;import com.gc.impl.TimeBookInterface;public class TimeBook implements TimeBookInterface {public void doAuditing(String name) {//审核数据的相关程序……}}(3)编写一个代理类,用来实现日志的输出,在该类中针对前面的接口TimeBookInterface 编程,而不针对具体的类,从而实现具体业务逻辑与日志输出代码。
TimeBookProxy.java 的示例代码如下://******* TimeBookProxy.java**************package com.gc.action;import org.apache.log4j.Level;import org.apache.log4j.Logger;import com.gc.impl.TimeBookInterface;public class TimeBookProxy {private Logger logger = Logger.getLogger(this.getClass().getName());Spring 从入门到精通·78·private TimeBookInterface timeBookInterface;//在该类中针对前面的接口TimeBookInterface 编程,而不针对具体的类public TimeBookProxy(TimeBookInterface timeBookInterface) {this.timeBookInterface = timeBookInterface;}//实际业务处理public void doAuditing(String name) {logger.log(, name + " 开始审核数据....");timeBookInterface.doAuditing(name);logger.log(, name + " 审核数据结束....");}}(4)修改测试程序TestHelloWorld,把类TimeBook 当作参数传入代理类TimeBookProxy 中,从而实现对具体负责考勤审核类TimeBook 的调用。