之前一直写.net,没玩过spring,一直没用过aop(面向切面编程)这类功能,当然不是说.net里面没有这类框架,企业库就可以微软企业库官网
开始上代码:
package com.jiankunking.common;
import java.lang.annotation.*;
/**
* @author jiankunking
* @Date: 2016/8/15
* @Time: 11:09
* @annotation OperationLogger
*/
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取
@Target(ElementType.METHOD)//目标是方法
@Documented//文档生成时,该注解将被包含在javadoc中,可去掉
public @interface OperationLogger
{
/**
* 模块名字
*/
String modelName() default "";
/**
* 操作类型
*/
String option();
}
@interface是用来自定义注释类型的。
注释的声明用@符号后面跟上这个注释类型的名字,再后面跟上括号,括号中列出这个注释中元 素/方法的key-value对。值必须是常量。
package com.jiankunking.common;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* @author jiankunking
* @Date: 2016/8/15
* @Time: 11:11
* @annotation SysLogAspect
*/
@Aspect
@Component
public class SysLogAspect
{
private static final Logger logger = Logger.getLogger(SysLogAspect.class);
/**
* 定义Pointcut,Pointcut的名称,此方法不能有返回值,该方法只是一个标示
*/
@Pointcut("@annotation(com.jiankunking.common.OperationLogger)")
public void controllerAspect()
{
System.out.println("我是一个切入点");
}
/**
* 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。
* @param joinPoint
*/
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint)
{
System.out.println("=====SysLogAspect前置通知开始=====");
//handleLog(joinPoint, null);
}
/**
* 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
* @param joinPoint
*/
@AfterReturning(pointcut = "controllerAspect()")
public void doAfter(JoinPoint joinPoint)
{
System.out.println("=====SysLogAspect后置通知开始=====");
//handleLog(joinPoint, null);
}
/**
* 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。
* @param joinPoint
* @param e
*/
@AfterThrowing(value = "controllerAspect()", throwing = "e")
public void doAfter(JoinPoint joinPoint, Exception e)
{
System.out.println("=====SysLogAspect异常通知开始=====");
//handleLog(joinPoint, e);
}
/**
* 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。
* @param joinPoint
*/
@Around("controllerAspect()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable
{
System.out.println("=====SysLogAspect 环绕通知开始=====");
//handleLog(joinPoint, null);
Object obj= joinPoint.proceed();
System.out.println("=====SysLogAspect 环绕通知结束=====");
return obj;
}
/**
* 日志处理
*
* @param joinPoint
* @param e
*/
private void handleLog(JoinPoint joinPoint, Exception e)
{
try
{
//获得注解
OperationLogger logger = giveController(joinPoint);
if (logger == null)
{
return;
}
String signature = joinPoint.getSignature().toString(); // 获取目标方法签名
String methodName = signature.substring(signature.lastIndexOf(".") + 1,
signature.indexOf("("));
String longTemp = joinPoint.getStaticPart().toLongString();
String classType = joinPoint.getTarget().getClass().getName();
Class> clazz = Class.forName(classType);
Method[] methods = clazz.getDeclaredMethods();
System.out.println("methodName: " + methodName);
for (Method method : methods)
{
if (method.isAnnotationPresent(OperationLogger.class)
&& method.getName().equals(methodName))
{
//OpLogger logger = method.getAnnotation(OpLogger.class);
String clazzName = clazz.getName();
System.out.println("clazzName: " + clazzName + ", methodName: "
+ methodName);
}
}
} catch (Exception exp)
{
logger.error("异常信息:{}", exp);
exp.printStackTrace();
}
}
/**
* 获得注解
* @param joinPoint
* @return
* @throws Exception
*/
private static OperationLogger giveController(JoinPoint joinPoint) throws Exception
{
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null)
{
return method.getAnnotation(OperationLogger.class);
}
return null;
}
}
Aspect通常用于将必要的但和业务无关的逻辑和业务逻辑分离。
Spring使用的AOP注解分为三个层次:
前提条件是在xml中放开了
<aop:aspectj-autoproxy proxy-target-class="true"/>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.mkyong.commongroupId>
<artifactId>spring-mvc-log4jartifactId>
<packaging>warpackaging>
<version>1.0-SNAPSHOTversion>
<name>SpringMVC + Log4jname>
<properties>
<jdk.version>1.7jdk.version>
<spring.version>4.3.2.RELEASEspring.version>
<log4j.version>2.6.2log4j.version>
<jstl.version>1.2jstl.version>
<servletapi.version>3.1.0servletapi.version>
<org.aspectj-version>1.7.4org.aspectj-version>
<cglib.version>3.1cglib.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-apiartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>org.apache.logging.log4jgroupId>
<artifactId>log4j-coreartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
<version>${jstl.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>${servletapi.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjrtartifactId>
<version>${org.aspectj-version}version>
dependency>
<dependency>
<groupId>javax.injectgroupId>
<artifactId>javax.injectartifactId>
<version>1version>
dependency>
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>${cglib.version}version>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.3version>
<configuration>
<source>${jdk.version}source>
<target>${jdk.version}target>
configuration>
plugin>
plugins>
build>
project>
<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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<bean id="logService" class="com.jiankunking.common.SysLogAspect">bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/value>
property>
<property name="suffix">
<value>.jspvalue>
property>
bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<mvc:annotation-driven/>
<context:component-scan base-package="com.jiankunking.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
context:component-scan>
<mvc:resources location="/resources/" mapping="/resources/**"/>
beans>
注解也写好了,spring也配置好了,在controller里面怎么用呢?
package com.jiankunking.controller;
import com.jiankunking.common.OperationLogger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping(value = "/Welcome", produces = "text/html;charset=UTF-8")
public class WelcomeController
{
@OperationLogger(modelName = "WelcomeController", option = "getWelcome")
@RequestMapping(value = "/getWelcome", method = RequestMethod.POST)
public void getWelcome()
{
//异常拦截测试
//int i = 9 / 0;
System.out.println("controller方法执行!");
}
}
如何测试呢?
从前端发起ajax请求controller,即可:
$.ajax({
type: "POST",
url: "/Welcome/getWelcome",
contentType: "application/json",
data: null,
success: function ()
{
// alert("22");
},
error: function ()
{
// alert("失败!");
}
});
由于这里是通过Spring的@Aspect注解实现的AOP,所以同一个类中的某个方法A(该方法没有注解标识)调用另一个有注解标识的方法B时,方法B上的注解是不会起作用的。
演示demo:
http://download.csdn.net/detail/xunzaosiyecao/9609918
xml方式实现aop拦截及aop基础知识参考:
xml实现aop拦截
Spring Boot 自定义注解方式拦截Controller等实现日志管理:
Spring Boot 自定义注解
个人微信公众号:
作者:jiankunking 出处:http://blog.csdn.net/jiankunking