javaee怎么打印spring aop 日志管理的aop日志

spring中注解AOP编程一个小问题.-Java/JavaEE-java-电脑编程网spring中注解AOP编程一个小问题.-Java/JavaEE作者:c02949 和相关&&写了一个接口,再写了一个bean,实现了上面的接口.这个没什么问题.这是MyInterceptor 代码Java code
package com.liyu.
import org.ectj.lang.annotation.A
import org.ectj.lang.annotation.B
import org.aspectj.lang.annotation.P
@Aspect
public class MyInterceptor {
@Pointcut(&execution (* com.liyu.service.impl.PersonServiceBean.*(..))&)
private void anyMethod() {}//声明一个切入点
@Before(&anyMethod()&)
public void doAccessCheck() {
System.out.println(&前置通知:&);
&?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:context=&http://www.springframework.org/schema/context&
xmlns:aop=&http://www.springframework.org/schema/aop&
xsi:schemaLocation=&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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd&&
&aop:aspectj-autoproxy&&/aop:aspectj-autoproxy&
&bean id=&myInterceptor& class=&com.liyu.service.MyInterceptor&&&/bean&
&bean id=&personServiceBean& class=&com.liyu.service.impl.PersonServiceBean&&&/bean&
测试代码Java code
package com.liyu.
import org.springframework.context.ApplicationC
import org.springframework.context.support.ClassPathXmlApplicationC
import com.liyu.service.impl.PersonServiceB
public class AOPtest {
public static void main(String[] args) {
ApplicationContext ctx= new ClassPathXmlApplicationContext(&beans.xml&);
//MyInterceptor mi=(MyInterceptor)ctx.getBean(&myInterceptor&);
PersonServiceBean ps=(PersonServiceBean)ctx.getBean(&personServiceBean&);
ps.save(&xxx&);
结果出错了:Java code
16:16:35 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@17bd6a1: display name [org.springframework.context.support.ClassPathXmlApplicationContext@17bd6a1]; startup date [Mon Jun 14 16:16:35 CST 2010]; root of context hierarchy
16:16:35 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
16:16:36 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@17bd6a1]: org.springframework.beans.factory.support.DefaultListableBeanFactory@618d26
16:16:36 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@618d26: defining beans [org.springframework.aop.config.internalAutoProxyCreator,myInterceptor,personServiceBean]; root of factory hierarchy
Exception in thread &main& .lang.ClassCastException: $Proxy6 cannot be cast to com.liyu.service.impl.PersonServiceBean
at com.liyu.test.AOPtest.main(AOPtest.:13)
两个bean单独测试,一切正常.谢谢大家!------回答---------------其他回答(40分)---------
这里用PersonServiceBean 实现的接口 ps=(这里用PersonServiceBean 实现的接口)ctx.getBean(&personServiceBean&);究其原因 我认为是 $Proxy6 cannot be cast to com.liyu.service.impl.PersonServiceBean 你准备吧代理类转化为PersonServiceBean 。你得看看底层aop实现的原理
相关资料:|||||||spring中注解AOP编程一个小问题.-Java/JavaEE来源网络,如有侵权请告知,即处理!编程Tags:                &                    1206人阅读
Javaweb(76)
在《【Spring】Spring3.0.5的下载、配置与Helloworld》()一文各位已经可能看到了。如果Spring不整合log4j直接启动,则会出现如下关于Spring整合log4j的警告。这个挺烦人的,一方面自己提倡高内聚,低耦合,另一方面,自己没有整合log4j就提出警告。我们程序猿写出来的程序就叫做“耦合”,它Spring就叫做“整合”。好吧!你只能同时搞明白,log4j是个什么鬼东西,Spring怎么整合log4j,两个问题:
log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.由于此前介绍的都是Spring在Java工程中简单示例,log4j必须在JavaWeb工程中运行才有意义,你同时还要搞明白Spring怎么在JavaWeb工程上面运行,Spring怎么在JavaWeb工程中整合log4j。
一、Spring与Log4j的下载
1、你首先要有这两个JavaWeb组件的jar包吧?不然怎么搞出来?Spring在《【Spring】Spring3.0.5的下载、配置与Helloworld》()一文中已经讲过怎么下载了。Log4j则打开Apache的官网()如下图,选择log4j-1.2.17.zip(Windows)或者log4j-1.2.17.tar.gz(Linux)。同样是Apache的东西,在一些高版本的Tomcat中还整合了这个东西,当然,你最好还是在WEB-INF\lib目录下补上这个包,以致于你的工程在所有Tomcat都能跑。
2、在Eclipse for JavaEE中新建一个名为SpringLog4j的Dynamic Web Project,还在解压之后,把spring-framework-3.0.5.RELEASE-dependencies的所有东西与spring-framework-3.0.5.RELEASE\dist中的所有Jar包,不包括那个LIBD文件,apache-log4j-1.2.17下的log4j-1.2.17.jar,拷贝到WEB\lib文件夹。
3、之后你的Eclipse for JavaEE如下所示。WEB-INF目录下的Web.xml、applicationContext.xml、log4j.properties与根目录下的Log4j.jsp是一会儿我们要写的东西。
二、Spring与Log4j的配置
1、Web.xml
首先是这个关于JavaWeb的工程的总配置位置。我们要在里面声明要使用Spring与Log4j。值得注意的Log4j的配置必须在Spring配置之前,否则如果先启动Spring,那个必须整合Log4j才不吐警告的Spring,由于Log4j还没有启动,找不到Spring,又会在任性地吐警告。当然,你设置那些什么优先级也行,不过,先启动的直接放前面,这个文件不是更好看吗?
&?xml version=&1.0& encoding=&UTF-8&?&
&web-app xmlns:xsi=&http://www.w3.org/2001/XMLSchema-instance&
xmlns=&/xml/ns/javaee&
xsi:schemaLocation=&/xml/ns/javaee /xml/ns/javaee/web-app_3_0.xsd&
version=&3.0&&
&!-- Log4j配置 --&
&listener&
&listener-class&org.springframework.web.util.Log4jConfigListener&/listener-class&
&/listener&
&!-- 指定Log4j的配置文件所在目录。默认配置在WEB-INF目录下 --&
&context-param&
&param-name&log4jConfigLocation&/param-name&
&param-value&/WEB-INF/log4j.properties&/param-value&
&/context-param&
&!-- Spring配置 --&
&listener&
&listener-class&org.springframework.web.context.ContextLoaderListener&/listener-class&
&/listener&
&!-- 指定Spring Bean的配置文件所在目录。默认配置在WEB-INF目录下 --&
&context-param&
&param-name&contextConfigLocation&/param-name&
&param-value&/WEB-INF/applicationContext.xml&/param-value&
&/context-param&
&/web-app&
2、log4j.properties
这家伙的后缀名是这么长,你有什么办法?必须照打,都是Linux那边带过来的主,你看看人家Windows的配置文件的后缀名仅仅就是ini3个字母!
#log4j.rootLogger = [ level ] , appenderName, appenderName, ...
log4j.rootLogger = all, console, R
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
log4j.appender.R = org.apache.log4j.RollingFileAppender
log4j.appender.R.File = c:/log.txt
log4j.appender.R.MaxFileSize = 500KB
log4j.appender.R.MaxBackupIndex = 1
log4j.appender.R.layout = org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] - %m%n这东西还加不了中文注释,给大家一行一行地讲。#后面还仅能写英文的东西,把我大天朝的程序猿放哪里?我就加个中文注释都不让!
首先第一部分是log4j的总配置部分,all代表debug,info,error,fatal四种类型的信息都会输出。一般不设置为all,这里只是为了让大家看到效果。因为那些debug,info信息对我们半点意义没有,还因为有很多系统内部的文件运行都会输出debug与info信息刷屏、刷版。关键是输出到磁盘的日志文件会极速递增,浪费磁盘空间。玩SQL Server的时候大家又不知道那个.ldb是多么恐怖?
因此第一部分,一般写成:
log4j.rootLogger = ERROR, console, R代表仅输出error与fatal错误。
之后的console,R分别代表在控制台与文件输出。同时在之后的代码必须配置好这个两输出。
第二部分控制台#Console
首先要使用log4j特定的包,这个没有什么好说,最后一句指明输出格式。一会儿大招对照输出结果就明白怎么回事了。
第三部分文件#File
log4j.appender.R.File=c:/log.txt是指这个Web工程错误日志皆输出到c:/log.txt。不要像网上那些大神输出一个什么.log后缀,关键是能够直接打开。
之后log4j.appender.R.MaxFileSize = 500KB指明这个log.txt文件大小最多为500KB,如果超过这个大小,自动开一个新文件,而log4j.appender.R.MaxBackupIndex=1指明此工程顶多只能有1个这个的日志文件。多了的话,新内容覆盖旧内容,就像那些闭路电视摄像头一样。
Log4j到这里就搞完了。
3、applicationContext.xml
之后是Spring的部分,由于这次根本就没有用Spring做任何东西,因此,这个applicationContext.xml这样写就行了:
&?xml version=&1.0& encoding=&UTF-8&?&
&beans xmlns:xsi=&http://www.w3.org/2001/XMLSchema-instance&
xmlns=&http://www.springframework.org/schema/beans&
xsi:schemaLocation=&http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd&&
&/beans&能删的我都删了。
4、Log4j.jsp
最后是在WebContent根目录下的Log4j.jsp。在里面写入如下代码,整个程序的入口就是这个地方。
Servlet我都不搞了,就是为了让大家直接看清楚问题的关键所在。
&%@ page language=&java& contentType=&text/ charset=UTF-8&
pageEncoding=&UTF-8& import=&org.apache.log4j.Logger&%&
Logger.getLogger(this.getClass()).fatal(&致命错误!&);
Logger.getLogger(this.getClass()).error(&出错信息!&);
Logger.getLogger(this.getClass()).info(&普通信息!&);
Logger.getLogger(this.getClass()).debug(&调试信息!&);
三、运行结果
把SpringLog4j这个JavaWeb工程挂到Tomcat里面,运行,之后在任意浏览器输入http://localhost:8080/SpringLog4j/Log4j.jsp,待网页成功加载之后,直接回到Eclipse则得到如下的运行结果,你输入一次网址刷新一次,则输出一次以下结果:
同时,你的C盘,则多出一个log.txt,里面的内容如下,可以看到,在程序运行的时候,Spring的运行会吐出很多无意义的DEBUG、INFO、TRACE的信息,对于我们来说,真正有用的最后面的四句话。因此,可以理解,为何在上面的log4j.properties(这个后缀名又难记,又长,再次鄙视之!)的第一部分一般不写all,只写ERROR,这就只输出ERROR以上等级的错误,也就是ERROR与FATAL。或者写成TRACE,输出TRACE、ERROR与FATAL信息。
09:54:34 [org.springframework.web.context.ContextLoader]-[INFO] - Root WebApplicationContext: initialization started
09:54:34 [org.springframework.web.context.support.XmlWebApplicationContext]-[INFO] - Refreshing Root WebApplicationContext: startup date [Sun May 10 09:54:34 CST 2015]; root of context hierarchy
09:54:34 [org.springframework.beans.factory.xml.XmlBeanDefinitionReader]-[INFO] - Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml]
09:54:34 [org.springframework.beans.factory.xml.DefaultDocumentLoader]-[DEBUG] - Using JAXP provider [com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl]
09:54:34 [org.springframework.beans.factory.xml.PluggableSchemaResolver]-[TRACE] - Trying to resolve XML entity with public id [null] and system id [http://www.springframework.org/schema/beans/spring-beans-3.0.xsd]
09:54:34 [org.springframework.beans.factory.xml.PluggableSchemaResolver]-[DEBUG] - Loading schema mappings from [META-INF/spring.schemas]
09:54:34 [org.springframework.beans.factory.xml.PluggableSchemaResolver]-[DEBUG] - Loaded schema mappings: {http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd=org/springframework/oxm/config/spring-oxm-3.0.xsd, http://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd, http://www.springframework.org/schema/jms/spring-jms-3.0.xsd=org/springframework/jms/config/spring-jms-3.0.xsd, http://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd, http://www.springframework.org/schema/aop/spring-aop-3.0.xsd=org/springframework/aop/config/spring-aop-3.0.xsd, http://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd, http://www.springframework.org/schema/oxm/spring-oxm.xsd=org/springframework/oxm/config/spring-oxm-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd, http://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd, http://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd, http://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-3.0.xsd, http://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd, http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd, http://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans-3.0.xsd, http://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd, http://www.springframework.org/schema/tx/spring-tx-2.5.xsd=org/springframework/transaction/config/spring-tx-2.5.xsd, http://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd, http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd=org/springframework/jdbc/config/spring-jdbc-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool-3.0.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd, http://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd, http://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd, http://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd, http://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd, http://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd, http://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd, http://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-3.0.xsd, http://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd, http://www.springframework.org/schema/jms/spring-jms-2.5.xsd=org/springframework/jms/config/spring-jms-2.5.xsd, http://www.springframework.org/schema/jms/spring-jms.xsd=org/springframework/jms/config/spring-jms-3.0.xsd, http://www.springframework.org/schema/aop/spring-aop-2.5.xsd=org/springframework/aop/config/spring-aop-2.5.xsd, http://www.springframework.org/schema/mvc/spring-mvc.xsd=org/springframework/web/servlet/config/spring-mvc-3.0.xsd, http://www.springframework.org/schema/jdbc/spring-jdbc.xsd=org/springframework/jdbc/config/spring-jdbc-3.0.xsd, http://www.springframework.org/schema/tx/spring-tx-2.0.xsd=org/springframework/transaction/config/spring-tx-2.0.xsd, http://www.springframework.org/schema/tx/spring-tx-3.0.xsd=org/springframework/transaction/config/spring-tx-3.0.xsd, http://www.springframework.org/schema/context/spring-context-3.0.xsd=org/springframework/context/config/spring-context-3.0.xsd, http://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-3.0.xsd, http://www.springframework.org/schema/util/spring-util-3.0.xsd=org/springframework/beans/factory/xml/spring-util-3.0.xsd, http://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd, http://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd, http://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd, http://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd}
09:54:34 [org.springframework.beans.factory.xml.PluggableSchemaResolver]-[DEBUG] - Found XML schema [http://www.springframework.org/schema/beans/spring-beans-3.0.xsd] in classpath: org/springframework/beans/factory/xml/spring-beans-3.0.xsd
09:54:34 [org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader]-[DEBUG] - Loading bean definitions
09:54:34 [org.springframework.beans.factory.xml.XmlBeanDefinitionReader]-[DEBUG] - Loaded 0 bean definitions from location pattern [/WEB-INF/applicationContext.xml]
09:54:34 [org.springframework.web.context.support.XmlWebApplicationContext]-[DEBUG] - Bean factory for Root WebApplicationContext: org.springframework.beans.factory.support.DefaultListableBeanFactory@5eedf162: defining beans []; root of factory hierarchy
09:54:34 [org.springframework.web.context.support.XmlWebApplicationContext]-[DEBUG] - Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@314b0824]
09:54:34 [org.springframework.web.context.support.XmlWebApplicationContext]-[DEBUG] - Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@708a538f]
09:54:34 [org.springframework.ui.context.support.UiApplicationContextUtils]-[DEBUG] - Unable to locate ThemeSource with name 'themeSource': using default [org.springframework.ui.context.support.ResourceBundleThemeSource@1fce66ba]
09:54:34 [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[INFO] - Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5eedf162: defining beans []; root of factory hierarchy
09:54:34 [org.springframework.web.context.support.XmlWebApplicationContext]-[DEBUG] - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@7cbc2c83]
09:54:34 [org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] - Returning cached instance of singleton bean 'lifecycleProcessor'
09:54:34 [org.springframework.web.context.support.XmlWebApplicationContext]-[TRACE] - Publishing event in Root WebApplicationContext: org.springframework.context.event.ContextRefreshedEvent[source=Root WebApplicationContext: startup date [Sun May 10 09:54:34 CST 2015]; root of context hierarchy]
09:54:34 [org.springframework.web.context.ContextLoader]-[DEBUG] - Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
09:54:34 [org.springframework.web.context.ContextLoader]-[INFO] - Root WebApplicationContext: initialization completed in 230 ms
09:54:48 [org.apache.jsp.Log4j_jsp]-[FATAL] - 致命错误!
09:54:48 [org.apache.jsp.Log4j_jsp]-[ERROR] - 出错信息!
09:54:48 [org.apache.jsp.Log4j_jsp]-[INFO] - 普通信息!
09:54:48 [org.apache.jsp.Log4j_jsp]-[DEBUG] - 调试信息!
Log4j一般不会像这样直接写在log4j.jsp中。一般处于那些try-catch异常结构中的catch里面,或许一些操作文件、数据库的关键数据之间,直接给程序员看的。程序猿有空看看那个在log.txt,也就像保安有空看看闭路电视,来确定你的WEB工程到底正不正常。可以成为系统运维的一部分。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:545841次
积分:11911
积分:11911
排名:第920名
原创:643篇
评论:214条
先用屏幕录制软件Freez Screen Video Capture录制屏幕,再把得到的AVI,利用GIF Movie Gear转化成GIF1088人阅读
Spring(51)
6.1.1& AOP是什么& & & & 考虑这样一个问题:需要对系统中的某些业务做日志记录,比如支付系统中的支付业务需要记录支付相关日志,对于支付系统可能相当复杂,比如可能有自己的支付系统,也可能引入第三方支付平台,面对这样的支付系统该如何解决呢?传统解决方案:& & & & & & & 1)日志部分提前公共类LogUtils,定义“longPayBegin”方法用于记录支付开始日志,“logPayEnd”用于记录支付结果:&&&&&&&&&&&&&& 2)支付部分,定义IPayService接口并定义支付方法“pay”,并定义了两个实现:“PointPayService”表示积分支付,“RMBPayService”表示人民币支付;并且在每个支付实现中支付逻辑和记录日志:&&&&&&& &&&&&& 3)支付实现很明显有重复代码,这个重复很明显可以使用模板设计模式消除重复:&&4)到此我们设计了一个可以复用的接口;但大家觉得这样记录日志会很好吗,有没有更好的解决方案?如果对积分支付方式添加统计功能,比如在支付时记录下用户总积分数、当前消费的积分数,那我们该如何做呢?直接修改源代码添加日志记录,这完全违背了面向对象最重要的原则之一:开闭原则(对扩展开放,对修改关闭)?&更好的解决方案:在我们的支付组件中由于使用了日志组件,即日志模块横切于支付组件,在传统程序设计中很难将日志组件分离出来,即不耦合我们的支付组件;因此面向方面编程AOP就诞生了,它能分离我们的组件,使组件完全不耦合:1)采用面向方面编程后,我们的支付组件看起来如下所示,代码中不再有日志组件的任何东西;&2)所以日志相关的提取到一个切面中,AOP实现者会在合适的时候将日志功能织入到我们的支付组件中去,从而完全解耦支付组件和日志组件。&看到这大家可能不是很理解,没关系,先往下看。&&面向方面编程(AOP):也可称为面向切面编程,是一种编程范式,提供从另一个角度来考虑程序结构从而完善面向对象编程(OOP)。&&&&&&& 在进行OOP开发时,都是基于对组件(比如类)进行开发,然后对组件进行组合,OOP最大问题就是无法解耦组件进行开发,比如我们上边举例,而AOP就是为了克服这个问题而出现的,它来进行这种耦合的分离。&&&&&& AOP为开发者提供一种进行横切关注点(比如日志关注点横切了支付关注点)分离并织入的机制,把横切关注点分离,然后通过某种技术织入到系统中,从而无耦合的完成了我们的功能。&6.1.2& 能干什么&&&&&& AOP主要用于横切关注点分离和织入,因此需要理解横切关注点和织入:关注点:可以认为是所关注的任何东西,比如上边的支付组件;关注点分离:将问题细化从而单独部分,即可以理解为不可再分割的组件,如上边的日志组件和支付组件;横切关注点:一个组件无法完成需要的功能,需要其他组件协作完成,如日志组件横切于支付组件;织入:横切关注点分离后,需要通过某种技术将横切关注点融合到系统中从而完成需要的功能,因此需要织入,织入可能在编译期、加载期、运行期等进行。横切关注点可能包含很多,比如非业务的:日志、事务处理、缓存、性能统计、权限控制等等这些非业务的基础功能;还可能是业务的:如某个业务组件横切于多个模块。如图6-1&图6-1 关注点与横切关注点&&&&&&& 传统支付形式,流水方式:&&&&&&&& 面向切面方式,先将横切关注点分离,再将横切关注点织入到支付系统中:&AOP能干什么:用于横切关注点的分离和织入横切关注点到系统;比如上边提到的日志等等;完善OOP;降低组件和模块之间的耦合性;使系统容易扩展;而且由于关注点分离从而可以获得组件的更好复用。&6.1.3& AOP的基本概念&&&&&& 在进行AOP开发前,先熟悉几个概念:连接点(Jointpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,Spring只支持方法执行连接点,在AOP中表示为“在哪里干”;切入点(Pointcut):选择一组相关连接点的模式,即可以认为连接点的集合,Spring支持perl5正则表达式和AspectJ切入点模式,Spring默认使用AspectJ语法,在AOP中表示为“在哪里干的集合”;通知(Advice):在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice),在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知;在AOP中表示为“干什么”;方面/切面(Aspect):横切关注点的模块化,比如上边提到的日志组件。可以认为是通知、引入和切入点的组合;在Spring中可以使用Schema和@AspectJ方式进行组织实现;在AOP中表示为“在哪干和干什么集合”;引入(inter-type declaration):也称为内部类型声明,为已有的类添加额外新的字段或方法,Spring允许引入新的接口(必须对应一个实现)到所有被代理对象(目标对象),&在AOP中表示为“干什么(引入什么)”;目标对象(Target Object):需要被织入横切关注点的对象,即该对象是切入点选择的对象,需要被通知的对象,从而也可称为“被通知对象”;由于Spring AOP 通过代理模式实现,从而这个对象永远是被代理对象,在AOP中表示为“对谁干”;AOP代理(AOP Proxy):AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是通过代理来对目标对象应用切面。在Spring中,AOP代理可以用JDK动态代理或CGLIB代理实现,而通过拦截器模型应用切面。织入(Weaving):织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期、类装载期、运行期进行。在AOP中,通过切入点选择目标对象的连接点,然后在目标对象的相应连接点处织入通知,而切入点和通知就是切面(横切关注点),而在目标对象连接点处应用切面的实现方式是通过AOP代理对象,如图6-2所示。图6-2 概念关系接下来再让我们具体看看Spring有哪些通知类型:前置通知(Before Advice):在切入点选择的连接点处的方法之前执行的通知,该通知不影响正常程序执行流程(除非该通知抛出异常,该异常将中断当前方法链的执行而返回)。后置通知(After Advice):在切入点选择的连接点处的方法之后执行的通知,包括如下类型的后置通知:后置返回通知(After returning Advice):在切入点选择的连接点处的方法正常执行完毕时执行的通知,必须是连接点处的方法没抛出任何异常正常返回时才调用后置通知。后置异常通知(After throwing Advice):&在切入点选择的连接点处的方法抛出异常返回时执行的通知,必须是连接点处的方法抛出任何异常返回时才调用异常通知。后置最终通知(After finally Advice):&在切入点选择的连接点处的方法返回时执行的通知,不管抛没抛出异常都执行,类似于Java中的finally块。环绕通知(Around Advices):环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等等。各种通知类型在UML序列图中的位置如图6-3所示:&图6-3 通知类型&6.1.4& AOP代理&&&&&& AOP代理就是AOP框架通过代理模式创建的对象,Spring使用JDK动态代理或CGLIB代理来实现,Spring缺省使用JDK动态代理来实现,从而任何接口都可别代理,如果被代理的对象实现不是接口将默认使用CGLIB代理,不过CGLIB代理当然也可应用到接口。&&&&&&&&AOP代理的目的就是将切面织入到目标对象。&&&&&&& 概念都将完了,接下来让我们看一下AOP的 HelloWorld!吧。&6.2.1& 准备环境&&&&&& 首先准备开发需要的jar包,请到spring-framework-3.0.5.RELEASE-dependencies.zip和spring-framework-3.0.5.RELEASE-with-docs中查找如下jar包:&&org.springframework.aop-3.0.5.RELEASE.jarcom.springsource.org.aspectj.weaver-1.6.8.RELEASE.jarcom.springsource.org.aopalliance-1.0.0.jarcom.springsource.net.sf.cglib-2.2.0.jar&&&&这些jar包添加到“Build Path”下6.2.2& 定义目标类&&&&&& 1)定义目标接口:&java代码:package&cn.javass.spring.chapter6.&&public&interface&IHelloWorldService&{&&&&&&public&void&sayHello();&&}&&&&&&&&& 2)定义目标接口实现:&java代码:package&cn.javass.spring.chapter6.service.&&import&cn.javass.spring.chapter6.service.IHelloWorldS&&public&class&HelloWorldService&implements&IHelloWorldService&{&&&&&&@Override&&&&&&public&void&sayHello()&{&&&&&&&&&&System.out.println(&============Hello&World!&);&&&&&&}&&}&&&&&&&&&&&& 注:在日常开发中最后将业务逻辑定义在一个专门的service包下,而实现定义在service包下的impl包中,服务接口以IXXXService形式,而服务实现就是XXXService,这就是规约设计,见名知义。当然可以使用公司内部更好的形式,只要大家都好理解就可以了。&6.2.2& 定义切面支持类&&&&&& 有了目标类,该定义切面了,切面就是通知和切入点的组合,而切面是通过配置方式定义的,因此这定义切面前,我们需要定义切面支持类,切面支持类提供了通知实现:&java代码:package&cn.javass.spring.chapter6.&&public&class&HelloWorldAspect&{&&&&&&&&&&&&&&&public&void&beforeAdvice()&{&&&&&&&&&&System.out.println(&===========before&advice&);&&}&&&&&&&&public&void&afterFinallyAdvice()&{&&&&&&&&&&System.out.println(&===========after&finally&advice&);&&&&&&}&&}&&&&&&&&& 此处HelloWorldAspect类不是真正的切面实现,只是定义了通知实现的类,在此我们可以把它看作就是缺少了切入点的切面。&&&&&&& 注:对于AOP相关类最后专门放到一个包下,如“aop”包,因为AOP是动态织入的,所以如果某个目标类被AOP拦截了并应用了通知,可能很难发现这个通知实现在哪个包里,因此推荐使用规约命名,方便以后维护人员查找相应的AOP实现。&6.2.3& 在XML中进行配置&&&&&& 有了通知实现,那就让我们来配置切面吧:&&&&&& 1)首先配置AOP需要aop命名空间,配置头如下:&java代码:&?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:aop=&http://www.springframework.org/schema/aop&&&&&&&&&&&xsi:schemaLocation=&&&&&&&&&&&&&&http:&&&&&&&&&&&&&http:&&&&&&&&&&&&&http:&&&&&&&&&&&&&http:&&&/beans&&&&&&&&&&&&&& 2)配置目标类:&java代码:&bean&id=&helloWorldService&&&class=&cn.javass.spring.chapter6.service.impl.HelloWorldService&/&&&&&&&&&&&&& 3)配置切面:&java代码:&bean&id=&aspect&&class=&cn.javass.spring.chapter6.aop.HelloWorldAspect&/&&&&aop:config&&&&aop:pointcut&id=&pointcut&&expression=&execution(*&cn.javass..*.*(..))&/&&&&&&&&aop:aspect&ref=&aspect&&&&&&&&&&&&&aop:before&pointcut-ref=&pointcut&&method=&beforeAdvice&/&&&&&&&&&&&&aop:after&pointcut=&execution(*&cn.javass..*.*(..))&&method=&afterFinallyAdvice&/&&&&&&&&/aop:aspect&&&&/aop:config&&&&&&&&&& 切入点使用&aop:config&标签下的&aop:pointcut&配置,expression属性用于定义切入点模式,默认是AspectJ语法,“execution(* cn.javass..*.*(..))”表示匹配cn.javass包及子包下的任何方法执行。&切面使用&aop:config&标签下的&aop:aspect&标签配置,其中“ref”用来引用切面支持类的方法。&前置通知使用&aop:aspect&标签下的&aop:before&标签来定义,pointcut-ref属性用于引用切入点Bean,而method用来引用切面通知实现类中的方法,该方法就是通知实现,即在目标类方法执行之前调用的方法。&最终通知使用&aop:aspect&标签下的&aop:after &标签来定义,切入点除了使用pointcut-ref属性来引用已经存在的切入点,也可以使用pointcut属性来定义,如pointcut=&execution(* cn.javass..*.*(..))&,method属性同样是指定通知实现,即在目标类方法执行之后调用的方法。&6.2.4 & &运行测试测试类非常简单,调用被代理Bean跟调用普通Bean完全一样,Spring AOP将为目标对象创建AOP代理,具体测试代码如下:&java代码:package&cn.javass.spring.chapter6;&&import&org.junit.T&&import&org.springframework.context.ApplicationC&&import&org.springframework.context.support.ClassPathXmlApplicationC&&import&cn.javass.spring.chapter6.service.IHelloWorldS&&import&cn.javass.spring.chapter6.service.IPayS&&public&class&AopTest&{&&&&&&@Test&&&&&&public&void&testHelloworld()&{&&&&&&&&&&ApplicationContext&ctx&=&&new&ClassPathXmlApplicationContext(&chapter6/helloworld.xml&);&&&&&&&&&&IHelloWorldService&helloworldService&=&&&&&&&&&&ctx.getBean(&helloWorldService&,&IHelloWorldService.class);&&&&&&&&&&helloworldService.sayHello();&&&&&&}&&}&&&&&&&&&&&& 该测试将输出如下如下内容:&java代码:===========before&advice&&============Hello&World!&&===========after&finally&advice&&&&& & & &从输出我们可以看出:前置通知在切入点选择的连接点(方法)之前允许,而后置通知将在连接点(方法)之后执行,具体生成AOP代理及执行过程如图6-4所示。&图6-4 Spring AOP框架生成AOP代理过程6.3& 基于Schema的AOP&&& 基于Schema的AOP从Spring2.0之后通过“aop”命名空间来定义切面、切入点及声明通知。&&& 在Spring配置文件中,所以AOP相关定义必须放在&aop:config&标签下,该标签下可以有&aop:pointcut&、&aop:advisor&、&aop:aspect&标签,配置顺序不可变。&aop:pointcut&:用来定义切入点,该切入点可以重用;&aop:advisor&:用来定义只有一个通知和一个切入点的切面;&aop:aspect&:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。&6.3.1& 声明切面&&& 切面就是包含切入点和通知的对象,在Spring容器中将被定义为一个Bean,Schema方式的切面需要一个切面支持Bean,该支持Bean的字段和方法提供了切面的状态和行为信息,并通过配置方式来指定切入点和通知实现。&&&& 切面使用&aop:aspect&标签指定,ref属性用来引用切面支持Bean。&&&& 切面支持Bean“aspectSupportBean”跟普通Bean完全一样使用,切面使用“ref”属性引用它。6.3.2& 声明切入点&&& 切入点在Spring中也是一个Bean,Bean定义方式可以有很三种方式:&&&&1)在&aop:config&标签下使用&aop:pointcut&声明一个切入点Bean,该切入点可以被多个切面使用,对于需要共享使用的切入点最好使用该方式,该切入点使用id属性指定Bean名字,在通知定义时使用pointcut-ref属性通过该id引用切入点,expression属性指定切入点表达式:&java代码:&aop:config&&&&&aop:pointcut&id=&pointcut&&expression=&execution(*&cn.javass..*.*(..))&/&&&&&aop:aspect&ref=&aspectSupportBean&&&&&&&&&aop:before&pointcut-ref=&pointcut&&method=&before&/&&&&&/aop:aspect&&&&/aop:config&&&&&&&&2)在&aop:aspect&标签下使用&aop:pointcut&声明一个切入点Bean,该切入点可以被多个切面使用,但一般该切入点只被该切面使用,当然也可以被其他切面使用,但最好不要那样使用,该切入点使用id属性指定Bean名字,在通知定义时使用pointcut-ref属性通过该id引用切入点,expression属性指定切入点表达式:&java代码:&aop:config&&&&&aop:aspect&ref=&aspectSupportBean&&&&&&&&&aop:pointcut&id=&&pointcut&&expression=&execution(*&cn.javass..*.*(..))&/&&&&&&&&aop:before&pointcut-ref=&pointcut&&method=&before&/&&&&&/aop:aspect&&&&/aop:config&&&&&&&&&3)匿名切入点Bean,可以在声明通知时通过pointcut属性指定切入点表达式,该切入点是匿名切入点,只被该通知使用:&java代码:&aop:config&&&&&aop:aspect&ref=&aspectSupportBean&&&&&&&&&&aop:after&pointcut=&execution(*&cn.javass..*.*(..))&&method=&afterFinallyAdvice&/&&&&&/aop:aspect&&&&/aop:config&&&&6.3.3& 声明通知基于Schema方式支持前边介绍的5中通知类型:一、前置通知:在切入点选择的方法之前执行,通过&aop:aspect&标签下的&aop:before&标签声明:&java代码:&aop:before&pointcut=&切入点表达式&&&pointcut-ref=&切入点Bean引用&&&method=&前置通知实现方法名&&&arg-names=&前置通知实现方法参数列表参数名字&/&&&&& & & & &pointcut和pointcut-ref:二者选一,指定切入点;& & & & &method:指定前置通知实现方法名,如果是多态需要加上参数类型,多个用“,”隔开,如beforeAdvice(java.lang.String);& & & & &arg-names:指定通知实现方法的参数名字,多个用“,”分隔,可选,类似于【3.1.2 构造器注入】中的参数名注入限制:在class文件中没生成变量调试信息是获取不到方法参数名字的,因此只有在类没生成变量调试信息时才需要使用arg-names属性来指定参数名,如arg-names=&param&表示通知实现方法的参数列表的第一个参数名字为“param”。&首先在cn.javass.spring.chapter6.service.IhelloWorldService定义一个测试方法:&java代码:public&void&sayBefore(String&param);&&&其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定义实现&java代码:@Override&&public&void&sayBefore(String&param)&{&&&&&&System.out.println(&============say&&&+&param);&&}&&&&第三在cn.javass.spring.chapter6.aop. HelloWorldAspect定义通知实现:&java代码:public&void&beforeAdvice(String&param)&{&&&&&&System.out.println(&===========before&advice&param:&&+&param);&&}&&&最后在chapter6/advice.xml配置文件中进行如下配置:&java代码:&bean&id=&helloWorldService&&class=&cn.javass.spring.chapter6.service.impl.HelloWorldService&/&&&&bean&id=&aspect&&class=&cn.javass.spring.chapter6.aop.HelloWorldAspect&/&&&&aop:config&&&&&&&&aop:aspect&ref=&aspect&&&&&&&&&&&&&aop:before&pointcut=&execution(*&cn.javass..*.sayBefore(..))&and&args(param)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&method=&beforeAdvice(java.lang.String)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&arg-names=&param&/&&&&&&&&/aop:aspect&&&&/aop:config&&&&&测试代码cn.javass.spring.chapter6.AopTest:&java代码:@Test&&public&void&testSchemaBeforeAdvice(){&&&&&&&System.out.println(&======================================&);&&&&&&&ApplicationContext&ctx&=&new&ClassPathXmlApplicationContext(&chapter6/advice.xml&);&&&&&&&IHelloWorldService&helloworldService&=&ctx.getBean(&helloWorldService&,&IHelloWorldService.class);&&&&&&&helloworldService.sayBefore(&before&);&&&&&&System.out.println(&======================================&);&&}&&&将输入:&&=====================================================before advice param:before============say before==========================================&&&&分析一下吧:1)切入点匹配:在配置中使用“execution(* cn.javass..*.sayAfterReturning(..)) ”匹配目标方法sayAfterReturning,该方法返回true;2)目标方法定义:使用method=&afterReturningAdvice&指定后置返回通知实现方法;3)目标方法参数命名:其中使用arg-names=&retVal&指定通知实现方法参数名为“retVal”;4)返回值命名:returning=&retVal&用于将目标返回值赋值给通知实现方法参数名为“retVal”的参数上。&&三、后置异常通知:在切入点选择的方法抛出异常时执行,通过&aop:aspect&标签下的&aop:after-throwing&标签声明:&java代码:&aop:after-throwing&pointcut=&切入点表达式&&&pointcut-ref=&切入点Bean引用&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&method=&后置异常通知实现方法名&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&arg-names=&后置异常通知实现方法参数列表参数名字&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&throwing=&将抛出的异常赋值给的通知实现方法参数名&/&&&&& & & & &pointcut和pointcut-ref:同前置通知同义;& & & & &method:同前置通知同义;& & & & &arg-names:同前置通知同义;& & & & &throwing:定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法;throwing限定了只有目标方法抛出的异常匹配与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行,对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。&首先在cn.javass.spring.chapter6.service.IhelloWorldService定义一个测试方法:&java代码:public&void&sayAfterThrowing();&&&&&&其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定义实现&java代码:@Override&&public&void&sayAfterThrowing()&{&&&&&&System.out.println(&============before&throwing&);&&&&&&throw&new&RuntimeException();&&}&&&第三在cn.javass.spring.chapter6.aop. HelloWorldAspect定义通知实现:&java代码:public&void&afterThrowingAdvice(Exception&exception)&{&&&&System.out.println(&===========after&throwing&advice&exception:&&+&exception);&&}&&&&最后在chapter6/advice.xml配置文件中接着前置通知配置的例子添加如下配置:&java代码:&aop:after-throwing&pointcut=&execution(*&cn.javass..*.sayAfterThrowing(..))&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&method=&afterThrowingAdvice&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&arg-names=&exception&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&throwing=&exception&/&&&&测试代码cn.javass.spring.chapter6.AopTest:&&java代码:@Test(expected&=&RuntimeException.class)&&public&void&testSchemaAfterThrowingAdvice()&{&&&&&&System.out.println(&======================================&);&&&&&&ApplicationContext&ctx&=&new&ClassPathXmlApplicationContext(&chapter6/advice.xml&);&&&&&&IHelloWorldService&helloworldService&=&ctx.getBean(&helloWorldService&,&IHelloWorldService.class);&&&&&&helloworldService.sayAfterThrowing();&&&&&&System.out.println(&======================================&);&&}&&将输入:&&==================================================before throwing===========after throwing advice exception:java.lang.RuntimeException======================================&&&&&6.3.4& 引入&&& Spring引入允许为目标对象引入新的接口,通过在& aop:aspect&标签内使用& aop:declare-parents&标签进行引入,定义方式如下:&java代码:&aop:declare-parents&&&&&&&&&&&&types-matching=&AspectJ语法类型表达式&&&&&&&&&&&&&implement-interface=引入的接口&&&&&&&&&&&&&&&&&&&&&&&&&&default-impl=&引入接口的默认实现&&&&&&&&&&&&&delegate-ref=&引入接口的默认实现Bean引用&/&&&&& & & & &types-matching:匹配需要引入接口的目标对象的AspectJ语法类型表达式;& & & & &implement-interface:定义需要引入的接口;& & & & &default-impl和delegate-ref:定义引入接口的默认实现,二者选一,default-impl是接口的默认实现类全限定名,而delegate-ref是默认的实现的委托Bean名;&接下来让我们练习一下吧:&&& 首先定义引入的接口及默认实现:&java代码:package&cn.javass.spring.chapter6.&&public&interface&IIntroductionService&{&&&&&&public&void&induct();&&}&&&&java代码:package&cn.javass.spring.chapter6.service.&&import&cn.javass.spring.chapter6.service.IIntroductionS&&public&class&IntroductiondService&implements&IIntroductionService&{&&&&&&@Override&&&&&&public&void&induct()&{&&&&&&&&&&System.out.println(&=========introduction&);&&&&&&}&&}&&&&其次在chapter6/advice.xml配置文件中接着前置通知配置的例子添加如下配置:&java代码:&aop:declare-parents&&&&&&types-matching=&cn.javass..*.IHelloWorldService+&&&&&&&implement-interface=&cn.javass.spring.chapter6.service.IIntroductionService&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&default-impl=&cn.javass.spring.chapter6.service.impl.IntroductiondService&/&&&&&&&最后测试一下吧,测试代码cn.javass.spring.chapter6.AopTest:&java代码:@Test&&public&void&testSchemaIntroduction()&{&&&&&&System.out.println(&======================================&);&&&&&&ApplicationContext&ctx&=&new&ClassPathXmlApplicationContext(&chapter6/advice.xml&);&&&&&&IIntroductionService&introductionService&=&&&&&&ctx.getBean(&helloWorldService&,&IIntroductionService.class);&&&&&&introductionService.induct();&&&&&&System.out.println(&======================================&);&&}&&&&&&&将输入:&&===============================================introduction======================================&&&分析一下吧:1)目标对象类型匹配:使用types-matching=&cn.javass..*.IHelloWorldService+&匹配IHelloWorldService接口的子类型,如HelloWorldService实现;2)引入接口定义:通过implement-interface属性表示引入的接口,如“cn.javass.spring.chapter6.service.IIntroductionService”。3)引入接口的实现:通过default-impl属性指定,如“cn.javass.spring.chapter6.service.impl.IntroductiondService”,也可以使用“delegate-ref”来指定实现的Bean。4)获取引入接口:如使用“ctx.getBean(&helloWorldService&, IIntroductionService.class);”可直接获取到引入的接口。&6.3.5 AdvisorAdvisor表示只有一个通知和一个切入点的切面,由于Spring AOP都是基于AOP联盟的拦截器模型的环绕通知的,所以引入Advisor来支持各种通知类型(如前置通知等5种),Advisor概念来自于Spring1.2对AOP的支持,在AspectJ中没有相应的概念对应。Advisor可以使用&aop:config&标签下的&aop:advisor&标签定义:&java代码:&aop:advisor&pointcut=&切入点表达式&&pointcut-ref=&切入点Bean引用&&&&&&&&&&&&&&&&&&&&&&&&advice-ref=&通知API实现引用&/&&&&& & & & &pointcut和pointcut-ref:二者选一,指定切入点表达式;& & & & &advice-ref:引用通知API实现Bean,如前置通知接口为MethodBeforeAdvice;&接下来让我们看一下示例吧:首先在cn.javass.spring.chapter6.service.IhelloWorldService定义一个测试方法:&java代码:public&void&sayAdvisorBefore(String&param);&&&其次在cn.javass.spring.chapter6.service.impl. HelloWorldService定义实现&java代码:@Override&&public&void&sayAdvisorBefore(String&param)&{&&&&&&System.out.println(&============say&&&+&param);&&}&&&第三定义前置通知API实现:&java代码:package&cn.javass.spring.chapter6.&&import&java.lang.reflect.M&&import&org.springframework.aop.MethodBeforeA&&public&class&BeforeAdviceImpl&implements&MethodBeforeAdvice&{&&&&&&@Override&&&&&&public&void&before(Method&method,&Object[]&args,&Object&target)&throws&Throwable&{&&&&&&&&&&System.out.println(&===========before&advice&);&&&&&&}&&}&&&&在chapter6/advice.xml配置文件中先添加通知实现Bean定义:&java代码:&&&&&&&bean&id=&beforeAdvice&&class=&cn.javass.spring.chapter6.aop.BeforeAdviceImpl&/&&&&&&&然后在&aop:config&标签下,添加Advisor定义,添加时注意顺序:&java代码:&aop:advisor&pointcut=&execution(*&cn.javass..*.sayAdvisorBefore(..))&&&&&&&&&&&&&&&&&&&&&&&&advice-ref=&beforeAdvice&/&&&&&&&测试代码cn.javass.spring.chapter6.AopTest:&java代码:@Test&&public&void&testSchemaAdvisor()&{&&&&&System.out.println(&======================================&);&&&&&ApplicationContext&ctx&=&new&ClassPathXmlApplicationContext(&chapter6/advice.xml&);&&&&&IHelloWorldService&helloworldService&=&&&&&ctx.getBean(&helloWorldService&,&IHelloWorldService.class);&&&&&helloworldService.sayAdvisorBefore(&haha&);&&&&&System.out.println(&======================================&);&&}&&&&将输入:&&=================================================before advice============say haha======================================&&&在此我们只介绍了前置通知API,其他类型的在后边章节介绍。&&& 不推荐使用Advisor,除了在进行事务控制的情况下,其他情况一般不推荐使用该方式,该方式属于侵入式设计,必须实现通知API。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1182121次
积分:23762
积分:23762
排名:第218名
原创:1008篇
转载:210篇
译文:14篇
评论:466条
文章:19篇
阅读:23078
阅读:7554
阅读:8645
文章:42篇
阅读:60064
文章:56篇
阅读:46735
文章:24篇
阅读:14757
文章:27篇
阅读:21628
阅读:4255
阅读:35555
文章:17篇
阅读:11514
文章:33篇
阅读:17263
文章:31篇
阅读:18445
文章:13篇
阅读:8675
文章:16篇
阅读:12379
阅读:5353
文章:10篇
阅读:7950
文章:25篇
阅读:19886
文章:10篇
阅读:5937
阅读:5867
文章:15篇
阅读:18458
文章:15篇
阅读:12462
文章:32篇
阅读:26190
阅读:7909
文章:39篇
阅读:32006
文章:16篇
阅读:10273
文章:16篇
阅读:12049
文章:13篇
阅读:10809
文章:20篇
阅读:15864
文章:86篇
阅读:77131

我要回帖

更多关于 spring boot aop 日志 的文章

 

随机推荐