介绍两种实现Spring AOP的代码。xml和@Aspectj注解
XML篇
此切面类中有一些方法在测试时可以
ApplicationContext.xml文件配置Spring相关信息
注意的就是xmlns:引用AOP的头部
<?xml version="1.0" encoding="UTF-8"?>
<!-- 查找最新的schemaLocation 访问 http://www.springframework.org/schema/ -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:task="http://www.springframework.org/schema/task" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
">
<!-- 利用Schema-based(xml配置)实现 AOP 用到的配置都放在aop:config标签里 start by lily 2015-12-18 -->
<aop:config>
<!-- 配置Aspect(切面类) -->
<aop:aspect id="myAspect" ref="logAspect">
<!-- 配置Pointcut(切入点),表示此路径下的所有类的方法全部可以切入 -->
<aop:pointcut id="logServer" expression="execution(* com.udbac.controller.*Controller.*(..))" />
<!-- 配置advice(通知) ,此通知中所有的method都需要在切面类(LogAspectN.java)中一一对应 stard -->
<aop:before method="before" pointcut-ref="logServer"/><!-- 前置通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="logServer"/><!-- 后置通知 -->
<!--还可配置异常通知,环绕通知,这里不具体写了-->
<!-- 配置advice end -->
</aop:aspect>
</aop:config>
<!--AOP 使用的切面类 -->
<bean id="logAspect" class="com.udbac.util.aop.LogAspectN"></bean>
<!-- AOP 用到的配置 end -->
</beans>
LogAspectN.java 切面类
本类中可以将所有执行* com.udbac.controller.Controller.(..)此路径下的类的方法全部切入进来
package com.udbac.util.aop;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.udbac.service.LogService;
/***
* Log切面类 ,使用配置XML方式
*
* @date 2015-12-21
* @author lily
*
*/
public class LogAspectN {
/**
* 日志管理 接口,此接口的实现类并没有实现其他业务,如果存在业务写在实现类即可。
*/
@Autowired(required = true)
private LogService logService;
/***
* 前置通知
* before对应ApplicationContext.xml中的<aop:before method="before" pointcut-ref="logServer"/><!-- 前置通知 -->
* method名称一定要对应上
*/
public void before() {
System.out.println("前置通知!!!");
}
/***
* 后置通知
*/
public void afterReturning(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
// 请求的IP
String ip = request.getRemoteAddr();
try {
// *========控制台输出=========*//
System.out.println("=====后置通知开始=====");
//方法名称
String methodName=joinPoint.getTarget().getClass().getName() + "."
+ joinPoint.getSignature().getName() + "()";
//方法描述
String s_function=getControllerMethodDescription(joinPoint);
//操作内容
String opContent = adminOptionContent(joinPoint.getArgs(), methodName);
System.out.println("请求方法:"+ methodName);
System.out.println("操作模块(方法描述):"+ s_function);
System.out.println("操作内容:"+ opContent);
//创建日志对象
com.udbac.model.Log log = new com.udbac.model.Log();
log.setUserid(logService.loginUserId());//设置管理员id
log.setParameter(opContent);//参数
log.setIp(ip);//ip
log.setMethod(methodName);//请求方法
log.setModule(s_function);//操作模块
log.setOperation("查询");//操作
//调用log日志接口,向数据库中增加日志数据
logService.inserlog(log);//添加日志
} catch (Exception ex) {
}
}
/**
* 获取注解中对方法的描述信息 用于Controller层注解
*
* @param joinPoint 切点
* @return 方法描述
* @throws Exception
*/
public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
//获取controller注解中的 name,Log是我在调用controller方法前注解的Log。此处Log可以替换成其他。
description = method.getAnnotation(Log. class).name();
break;
}
}
}
return description;
}
/**
* 使用Java反射来获取被拦截方法(insert、update)的参数值,
* 将参数值拼接为操作内容
*/
public String adminOptionContent(Object[] args, String mName) throws Exception{
if (args == null) {
return null;
}
StringBuffer rs = new StringBuffer();
rs.append(mName);
String className = null;
int index = 1;
// 遍历参数对象
for (Object info : args) {
//获取对象类型
className = info.getClass().getName();
className = className.substring(className.lastIndexOf(".") + 1);
rs.append("[参数" + index + ",类型:" + className + ",值:");
// 获取对象的所有方法
Method[] methods = info.getClass().getDeclaredMethods();
// 遍历方法,判断get方法
for (Method method : methods) {
String methodName = method.getName();
// 判断是不是get方法
if (methodName.indexOf("get") == -1) {// 不是get方法
continue;// 不处理
}
Object rsValue = null;
try {
// 调用get方法,获取返回值
rsValue = method.invoke(info);
if (rsValue == null) {//没有返回值
continue;
}
} catch (Exception e) {
continue;
}
//将值加入内容中
rs.append("(" + methodName + " : " + rsValue + ")");
}
rs.append("]");
index++;
}
return rs.toString();
}
}
LogService.java接口
LogService类就是在LogAspectN 类中 引用的接口
例如,在LogAspectN.java中有如下代码:
@Autowired(required = true)
private LogService logService;
package com.udbac.service;
import com.udbac.model.Log;
/**
* 日志记录业务逻辑接口
*/
public interface LogService {
/**
* 日志记录
* @param log
*/
public void inserlog(Log log);
/**
* 获取登录管理员ID
*/
public Long loginUserId();
}
LogServiceImpl.java实现类
package com.udbac.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import com.udbac.service.LogService;
import com.udbac.dao.LogMapper;
import com.udbac.model.Log;
/**
* 日志记录业务逻辑接口实现类
* @date 2015-12-18
* @author lily
*/
public class LogServiceImpl implements LogService{
/***
* 由于使用的是MyBatis + Spring MVC结构,这里需要引用MyBatis使用interface
*/
@Autowired
private LogMapper logMapper;
public void inserlog(Log log) {
logMapper.insert(log);//调用SQL,sql使用了MyBatis,所以也给insert方法提供了interface
//在实现类里可以处理其他具体业务,这里只做一个测试输出
System.out.println("增加日志具体业务!!!!+++++++++++++++++++++++");
}
@Override
public Long loginUserId() {
// TODO Auto-generated method stub
return null;
}
}
其实,在这里大部分Spring AOP的代码已经写完了,至于入库的部分为了以后自己参考也拿出来方便以后查看
LogMapper.java(处理SQL的接口)
本类中的insert()方法正是LogServiceImpl 类中调用的logMapper.insert(log)
package com.udbac.dao;
import com.udbac.model.Log;
/**
* 日志记录Mapper
*
* @date 2015-12-18
* @author lily
*
*/
public interface LogMapper {
/****
* 添加系统操作日志
* @author lily
* @date 2015-12-18
* @param log
*/
public void insert(Log log);
}
LogMapper.xml (Mybatis中的SQL)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.udbac.dao.LogMapper">
<!-- 添加日志记录 -->
<!-- <select id="select">
select * from tb_virp_system_log();
</select> -->
<insert id="insert" parameterType="map">
INSERT INTO tb_virp_system_log(user_id,create_date,module,method,actions,ip,parameter)
VALUES(#{userid},to_char(now(),'yyyy-mm-dd hh24:hh:ss')::timestamp,#{module},#{method},#{operation},#{ip},#{parameter});
</insert>
</mapper>
使用XML的方式实现AOP大概就是如此,主要在ApplicationContext.xml文件配置以及对应的切面类(LogAspectN )。只要能切入进来,调用相关的业务方法就简单了
下一篇将介绍使用@Aspectj注解方式实现Spring AOP。