发表于: 2018-06-03 21:15:19
1 1150
今天主要学习了springmvc aop的知识点,这个一开始我不知道是什么,找了很多档案目录,其中一个很抽象的解释了什么是aop,
AOP图解
面向切面,面向方面,也叫刀削面。
这个图是不是很灵性,当时看的时候很懵逼(并且有一种想吃刀削面的想法)
具体来说的话,蘸料是切面(增强),刀削面是切入点,把蘸料加入到刀削面中,就是切面(要切入的代码段)切入到切入点中去。即AOP,
这应该也就是面向切面的编程aop,
看了那么多字面姿势(知识),应该要去动手做一做切面到底是要干什么了,
一开始没有方向怎么处理这个(查了很多的材料)
查到aop切面编程,记录日志的打印
首先配置依赖包
(依赖包的地址)
http://maven.outofmemory.cn/org.aspectj/aspectjweaver/1.7.4/
在这里添加依赖包,
(参考文档)
https://blog.csdn.net/turleslove/article/details/52575771
创建aop的类
1,controller aop
@Aspect 注解表示这是一个切面
@Component 表示这是一个bean,由Spring进行管理
@Around(value = "execution(* com.jnshu.controller.*.*(..))") 表示对com.jnshu.ControllerRest 这个类中的所有方法进行切面操作
@Aspect
@Component
public class TimerController {
private static Log logger = LogFactory.getLog(TimerController.class);
//一分钟,即60000ms
private static final long ONE_MINUTE = 60000;
//
@Around(value = "execution (* com.jnshu.controller.*.*(..))") //这里定义了controller
public Object timeAround(ProceedingJoinPoint joinPoint) throws Throwable {
//定义返回对象、得到方法需要的参数
Object obj = null; //对象
Object[] args = joinPoint.getArgs();
long startTime = System.currentTimeMillis();
try {
obj = joinPoint.proceed(args);
} catch (Throwable e) {
logger.error("统计某方法执行消耗时环绕");
}
// 获取执行的方法名
long endTime = System.currentTimeMillis();
//方法声明的两个组件构成了方法签名 - 方法的名称和参数类型。
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
//方法后面接收的就是Class类的对象,而如:String.class、int.class这些字节码才是Class类的对象
String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
//打印耗时的信息
this.printExecTime(methodName, startTime, endTime);
return obj;}
2,db.aop
@Around(value = "execution (* com.jnshu.service.*.*(..))")
//定义service的统计执行时间
public Object serviceTime(ProceedingJoinPoint joinPoint)throws Throwable {
//定义返回对象,需要的参数值
Object db = null;
Object[] arg = joinPoint.getArgs();
long stTime = System.currentTimeMillis();
//判断
try {
db = joinPoint.proceed(arg);
//catch 错误执行
} catch (Throwable e) {
logger.error("统计某方法执行消耗时环绕");
}
//获取执行方法名
long endtime = System.currentTimeMillis();
//方法声明的两个组件构成了方法签名 - 方法的名称和参数类型。
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
//方法后面接收的就是Class类的对象,而如:String.class、int.class这些字节码才是Class类的对象
String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
//打印消耗信息
this.printExecTime(methodName, stTime, endtime);
return db;
}
private void printExecTime(String methodName, long startTime, long endTime) {
long diffTime = endTime - startTime;
System.out.println("-----" + methodName + "方法执行耗时:" +diffTime + "ms");
if (diffTime > ONE_MINUTE) {
logger.warn("-----" + methodName + "方法执行耗时:" + diffTime + "ms");
}
}
}
SpringMVC关于AOP拦截controller的注意事项
controller.aop 的切面配置文件必须放在springmvc 目录下。
<!-- 开启自动切面代理 -->
<aop:aspectj-autoproxy/>
<!-- controller aop -->
<bean name="timerController" class="com.jnshu.aop.TimerController"/>
</beans>
输出成功
1.Controller层和你自己定义的切面,必须在相同的spring上下文中(context).
Usually people define their controllers in the dispatch-servlet.xml or xxx-servlet.xml and their service beans (including the aspects) in the main applicationContext.xml. It will not work.
2.通常大家会把 controllers 定义在dispatch-servlet.xml 或者 xxx-servlet.xml 这样的配置文件中,但是把自定义的切面放在spring的主配置文件 applicationContext.xml中。这样子导致controller和你的切面不在同一个context中,从而你的切面类逻辑不会拦截对应的controller.
When Spring initializes the MVC context, it will create a proxy for your controller but if your aspects are not in the same context, Spring will not create interceptors for them.
3.当spring初始化MVC的context的时候,它会同时为controller 创建代理,但是如果自定义切面没有和mvc在同一个context中,那么你的切面是不会去拦截这些controller 的
service.aop 的切面文件必须放在spring目录下
<!-- service aop -->
<context:component-scan base-package="com.jnshu.aop"/>
<context:component-scan base-package="com.jnshu.service"/>
<aop:aspectj-autoproxy/>
输出成功
重新配置了一下log4j.xml的文件,
pom.xml文件log4j 依赖包
<!-- slf4j日志包 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
web.xml文件中配置log4j
监听器一定要在前面,
<!-- 配置log4j.xml监听器 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>WEB-INF/config/log4j.xml</param-value>
</context-param>
<!-- 配置log4j.xml变量,如果需要动态的就使用下面方式,使用方法${name} -->
<context-param>
<param-name>controller</param-name>
<param-value>controller-log</param-value>
</context-param>
<context-param>
<param-name>loggingLevel</param-name>
<param-value>info</param-value>
</context-param>
<!-- 加载log4j配置文件 -->
<listener>
<!-- 在Spring 4.2.1中已经将其标记为过时了.如果使用spring4.2.1以上的版本又会造成不兼容
Log4jConfigListener必须要在Spring的Listener之前。 -->
<listener-class>org.springframework.web.util.Log4jConfigListener
</listener-class>
</listener>
log4j.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--log4j.xml 配置文件 优先于 log4j.properties 配置文件 -->
<!-- * 1. 一个appender子元素定义一个日志输出目的地 * 2. 一个logger子元素定义一个日志写出器 -->
<!-- ========================== 自定义输出格式说明================================ -->
<!-- %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL -->
<!-- %r 输出自应用启动到输出该log信息耗费的毫秒数 -->
<!-- %c 输出所属的类目,通常就是所在类的全名 -->
<!-- %t 输出产生该日志事件的线程名 -->
<!-- %n 输出一个回车换行符,Windows平台为“/r/n”,Unix平台为“/n” -->
<!-- %d 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS} -->
<!-- 输出类似:2002年10月18日 22:10:28,921 -->
<!-- %l 输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10) -->
<!-- ========================================================================== -->
<!-- ========================== 输出方式说明================================ -->
<!-- Log4j提供的appender有以下几种: -->
<!-- org.apache.log4j.ConsoleAppender(控制台), -->
<!-- org.apache.log4j.FileAppender(文件), -->
<!-- org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件), -->
<!-- org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件), -->
<!-- org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方) -->
<!-- ========================================================================== -->
<log4j:configuration>
<!-- 输出到控制台 -->
<!-- 可以配置多个appender来对应不同的输出,如文件输出,sql输出,控制台输出,邮件输出等 -->
<!-- [控制台STDOUT] 不同的输出类型对应着不同的calss,如控制台输出class对应着 org.apache.log4j.ConsoleAppender -->
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout"><!-- loyout表示输出方式,可以多种,class值区分,PatternLayout表示自定义格式 -->
<param name="ConversionPattern" value="%d{ISO8601} 耗时:%r [日志来自:%-40.40c{3} 日志类型: %-5p 日志内容:%m]%n" />
</layout>
</appender>
<!-- 输出到日志文件 每天一个日志 -->
<appender name="LOGDEBUG" class="org.apache.log4j.DailyRollingFileAppender">
<!-- Threshold屏蔽级别之下的日志输出 -->
<param name="Threshold" value="DEBUG" />
<param name="encoding" value="UTF-8" />
<param name="File" value="${webapp.root}/logs/debug-log.log" />
<param name="DatePattern" value="'debug_'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} 耗时:%r [日志来自:%-40.40c{3} 日志类型: %-5p 日志内容:%m]%n" />
</layout>
</appender>
<appender name="LOGINFO" class="org.apache.log4j.DailyRollingFileAppender">
<!-- <param name="Threshold" value="INFO" /> -->
<param name="encoding" value="UTF-8" />
<param name="File" value="${webapp.root}/logs/logInf-log.log" />
<param name="DatePattern" value="'info_'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} 耗时:%r [日志来自:%-40.40c{3} 日志类型: %-5p 日志内容:%m]%n" />
</layout>
<!--限制输出级别 -->
<!-- filter过滤器设置输出的级别:ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF
如果levelMax为warn则输出的是debug到warn不会有error和fatal -->
<!-- 输出所有日志 ALL -->
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="INFO" />
</filter>
</appender>
<appender name="LOGERROR" class="org.apache.log4j.DailyRollingFileAppender">
<!-- <param name="Threshold" value="ERROR" /> -->
<param name="encoding" value="UTF-8" />
<param name="File" value="${webapp.root}/logs/error-log.log" />
<param name="DatePattern" value="'error_'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} 耗时:%r [日志来自:%-40.40c{3} 日志类型: %-5p 日志内容:%m]%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="ERROR" />
<param name="LevelMax" value="ERROR" />
</filter>
</appender>
<!-- 指定类appender 输出指定类日志到指定位置 -->
<appender name="TimerController" class="org.apache.log4j.DailyRollingFileAppender">
<param name="encoding" value="UTF-8" />
<param name="File" value="${webapp.root}/logs/TimerController-log.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %t %5p [%c:%L] - %m%n" />
</layout>
</appender>
<appender name="ControllerRest" class="org.apache.log4j.DailyRollingFileAppender">
<param name="encoding" value="UTF-8" />
<param name="File" value="${webapp.root}/logs/ControllerRest-log.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd'.log'" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %t %5p [%c:%L] - %m%n" />
</layout>
</appender>
<!-- additivity="false" 不继承root-->
<category name="ControllerRest" additivity="false">
<!-- 输出所有级别日志 -->
<level value="ALL" />
<appender-ref ref="ControllerRest" />
<!-- 输出到控制台 -->
<appender-ref ref="CONSOLE" />
</category>
<category name="TimerController" additivity="false">
<level value="All" />
<appender-ref ref="TimerController" />
<!-- 输出到控制台 -->
<appender-ref ref="CONSOLE" />
</category>
<!-- 日志的总开关设置 包括日志级别和 appender -->
<!-- logger的作用: 1.[name属性]:指定你定义Logger对象时候的name -->
<!-- 2. additivity : children-logger是否使用 rootLogger的配置, additivity在log4j默认为true。 -->
<!-- 这解释了为什么有些时候,一个日志信息在屏幕上会有多次输出。 -->
<!-- 3.还可以指定level(输出级别)、appender-ref(指定哪个append) -->
<root>
<!-- ALL < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
<!-- all为输出所有级别日志-->
<level value="DEBUG" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="LOGDEBUG" />
<appender-ref ref="LOGINFO" />
<appender-ref ref="LOGERROR" />
</root>
</log4j:configuration>
配置成功后 控制台的输出
遇到的问题:
期间
遇到这种报错,通过查看日志解决,
看看这里是不是少了什么标点符号,我一开始这里少了个点,定位不到具体的目录一直报错,
还有就是上面说的aop配置文件的问题,已经说明的很清楚了,在哪个下面配置扫描aop,
今天完成的事情:初步完成了aop日志的统计访问db连接的时间,
明天的计划:部署到服务器上编辑shell脚本运行查看
今天遇到的困难:一堆,如上看图都写出来了,而且都已经解决的差不多了。
收获:就是对AOP有了新的了解,还有对日志打印认识很重要,对linux系统,慢慢的熟悉起来。
------------------------------------------------------------我是分割线----------------------------------------------------------------
生活帖:
今天是6月4号啦,对于我来说已经来修真院一个月了,半个月前,也写了一篇生活帖,今天更新一下.
来修真院已经一个月了,剩下还有不到三个月的时间,想想刚来的时候,对java这一块什么都不懂,到现在的慢慢
熟悉,也算是从没有到有的一个进步的过程,其实我想来这里的百分之九十的人,都希望能够改变自己,不让自己
成为自己讨厌的那种人,有的也许是真的对编程,对it的热爱,也有的就是为了以后的生活能够更好的提升,不管
怎么说方向是好的,来这里说时间吧其实过得也很快,每次写完一大串代码的时候发现已经过去好几个小时,当我
们投入到一件事情当中的时候,时间已变成了不在那么重要,每天的早起晚睡已成为了常态,在做任务的时候遇到
难题可能自己会愁很多天,在做任务二的时候对jsp和restful,这两个知识点真的是快把自己逼到了绝路了,一个
restful的问题,可能对于刚接触的我是模糊的,当时对这个概念完全没有理解,不知道有什么用,查了也不懂,跟
着别人写代码,完全没逻辑,干脆先弄懂再说,于是花了三四天时间,查询各种示例资料,只为弄懂一个知识点,
后来慢慢的也会想通,会知道怎么写,师兄的日报,对于我们新手来说真的是条捷径,但是我感觉还是要多问自为
什么,为什么要做么做,为什么要这么写,为什么一定要写在这里,一定要多问自己一些为什么,这样对于我们的
提升也很大,来了这么久了没出过光谷,连小姐姐都没见到过了,每天的时间就是码代码,和吃饭睡觉,这几天还
有小矛盾,具体什么原因,就说了一句话“你每天都很忙么。” 是挺忙的,每天都要完成任务,在有限的时间里
做这么多事情,狠不得自己能分身一个出来。在修真院的时间是有限的,所以我想在有限的时间里能够加油努力做
到自己力所能及的事情,不让自己来这里最后带着后悔离开,也希望下个半月的生活帖 能够吹一次牛逼,说我做
到了。
晚安!
3:00
2018-06-04
评论