基于配置的Spring AOP实现安全、日志的功能

Spring aop 是面向切面编程

什么是面向切面?

AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下,给程序动态的统一添加功能的一种技术(比如:事务,安全,日志等)。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

如何使用?

我们这里讲解基于spring aop来记录日志
1 先配置需要使用到的jar,我们采用的Maven来实现,在springmvc的基础上还需要加入如下引用pom.xml:
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.7</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.7</version>
</dependency>
2 配置spring的applicationContext.xml文件
<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:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:cache="http://www.springframework.org/schema/cache"
	xsi:schemaLocation="
     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
     http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
     http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
     http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">
	<!-- 激活spring的注解. -->
	<context:annotation-config />
	<!--注解扫描包路径 -->
	<context:component-scan base-package="com.*;com.csm.*;com.adapter.*" />
	<!-- 激活自动代理功能 -->
	<aop:aspectj-autoproxy proxy-target-class="true" />
</beans>

3 为Aspect切面类添加注解:

如果需要排除某些类,则在execution的前面加!

package com.hdbs.comm.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 系统服务组件Aspect切面Bean
 * @author  yuejing
 * @email   yuejing0129@163.com 
 * @date    2015年12月24日 下午3:36:58 
 * @version 1.0.0
 */
@Component
@Aspect
public class MonitorAspect {
	private final static Logger LOGGER = Logger.getLogger(MonitorAspect.class);

	/**
	 * 配置切入点,该方法无方法体,主要为方便同类中其他方法使用此处配置的切入点
	 */
	@Pointcut("execution(* com.hdbs.comm.service..*(..)) || execution(* com.hdbs.unit.service..*(..))")
	public void aspect() {
	}

	/**
	 * 配置前置通知,使用在方法aspect()上注册的切入点
	 * 同时接受JoinPoint切入点对象,可以没有该参数
	 * @param joinPoint
	 */
	@Before("aspect()")
	public void before(JoinPoint joinPoint){
		/*if(LOGGER.isInfoEnabled()){
			LOGGER.info("before " + joinPoint);
		}*/
	}

	//配置后置通知,使用在方法aspect()上注册的切入点
	@After("aspect()")
	public void after(JoinPoint joinPoint){
		/*if(LOGGER.isInfoEnabled()){
			LOGGER.info("after " + joinPoint);
		}*/
	}

	/**
	 * 配置环绕通知,使用在方法aspect()上注册的切入点
	 * @param joinPoint
	 * @return
	 */
	@Around("aspect()")
	public Object around(JoinPoint joinPoint){
		long start = System.currentTimeMillis();
		Object obj = null;
		try {
			obj = ((ProceedingJoinPoint) joinPoint).proceed();
			long end = System.currentTimeMillis();
			if(LOGGER.isInfoEnabled()){
				LOGGER.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms!");
			}
		} catch (Throwable e) {
			long end = System.currentTimeMillis();
			if(LOGGER.isInfoEnabled()){
				LOGGER.info("around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());
			}
		}
		return obj;
	}

	/**
	 * 配置后置返回通知,使用在方法aspect()上注册的切入点
	 * @param joinPoint
	 */
	@AfterReturning("aspect()")
	public void afterReturn(JoinPoint joinPoint){
		/*if(LOGGER.isInfoEnabled()){
			LOGGER.info("afterReturn " + joinPoint);
		}*/
	}

	/**
	 * 配置抛出异常后通知,使用在方法aspect()上注册的切入点
	 * @param joinPoint
	 * @param ex
	 */
	@AfterThrowing(pointcut="aspect()", throwing="ex")
	public void afterThrow(JoinPoint joinPoint, Exception ex){
		/*if(LOGGER.isInfoEnabled()){
			LOGGER.info("afterThrow " + joinPoint + "\t" + ex.getMessage());
		}*/
	}
}

4 在对应的包路径下增加类

package com.hdbs.comm.service;

import org.springframework.stereotype.Component;

@Component
public class LogService {

	public String getLog(String name) {
		return "日志名称为: " + name;
	}
}

5 测试类

package com.hdbs.comm;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;

import com.hdbs.comm.service.LogService;
import com.hdbs.comm.service.SysMonitorService;

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(locations = { "classpath*:applicationContext.xml" })  
@TransactionConfiguration(defaultRollback = false)
public class SysMonitorTest {
	
	private final static Logger LOGGER = Logger.getLogger(SysMonitorTest.class);
	
	@Autowired
	private LogService logService;
	
	/**
	 * 添加医院信息
	 */
	@Test
	public void aspect() {
		String str = logService.getLog("大宝天天见");
		LOGGER.info("str=" + str);
	}
}

6 运行测试类,然后就可以看到日志了

around execution(String com.hdbs.comm.service.LogService.getLog(String))	Use time : 8 ms!
str=日志名称为: 大宝天天见
文章到这里结束了,谢谢大家感谢您的阅读,希望对您有帮助,本文版权归 #惊讶# 所有
评论 (0)