Spring-AOP之aspectj注解方式

一、简介
 1、AOP用在哪些方面:AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理日志管理权限控制异常处理等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
 2、AOP中的概念:
    Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是横切性关注点的抽象.
   joinpoint(连接点):所谓连接点是指那些被拦截到的点(可以是方法、属性、或者类的初始化时机(可以是Action层、Service层、dao层))。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)
   Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义,也即joinpoint的集合.
   Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
   Target(目标对象):代理的目标对象
   Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.
   Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.

 3、AOP带来的好处::降低模块的耦合度;使系统容易扩展;更好的代码复用性

二、通过注解方式实现Spring的AOP

1.定义业务类

接口:

package cn.slimsmart.spring.demo.aop;

public interface UserService {
	String save(String name);
	String update(String name);
	String delete(String name);
}
实现:

package cn.slimsmart.spring.demo.aop;

import org.springframework.stereotype.Service;

@Service  <span style="font-family: Arial, Helvetica, sans-serif;">//使用自动注解的方式实例化并初始化该类</span>
public class UserServiceImpl implements UserService{

	@Override
	public String save(String name) {
		System.out.println("--------save");
		return "save";
	}

	@Override
	public String update(String name) {
		System.out.println("--------update");
		System.out.println(1/0);
		return "update";
	}

	@Override
	public String delete(String name) {
		System.out.println("--------delete");
		return "delete";
	}

}
2.定义切面类

package cn.slimsmart.spring.demo.aop;

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 : 标记为切面类
//@Pointcut : 指定匹配切点集合
//@Before : 指定前置通知,value中指定切入点匹配
//@AfterReturning :后置通知,具有可以指定返回值
//@AfterThrowing :异常通知
//@Around 环绕通知 环绕通知的方法中一定要有ProceedingJoinPoint 参数,与Filter中的  doFilter方法类似
//注意:前置/后置/异常通知的函数都没有返回值,只有环绕通知有返回值
@Component //使用自动注解的方式实例化并初始化该类
@Aspect
public class TestInterceptor {

	//如果要设置多个切点可以使用 || 拼接
	@Pointcut("execution(* cn.slimsmart.spring.demo.aop.UserServiceImpl.*(..))")
	private void anyMethod() {
	}// 定义一个切入点

	@Before(value="anyMethod()")
	public void doBefore(JoinPoint joinPoint) {
		System.out.println("前置通知");
	}

	@AfterReturning(value="anyMethod()",returning="result")
	public void doAfter(JoinPoint jp, String result) {
		System.out.println("后置通知");
	}

	@After("anyMethod()")
	public void after() {
		System.out.println("最终通知");
	}

	@AfterThrowing(value="execution(* cn.slimsmart.spring.demo.aop.*.*(..))",throwing="e")
	public void doAfterThrow(JoinPoint joinPoint, Throwable e) {
		System.out.println("异常通知");
	}

	@Around("execution(* cn.slimsmart.spring.demo.aop.*.*(..))")
	public Object doBasicProfiling(ProceedingJoinPoint joinPoint) throws Throwable {
		System.out.println("进入环绕通知");
		System.out.println("目标类名称:"+joinPoint.getTarget().getClass().getName());
		System.out.println("方法名称:"+joinPoint.getSignature().getName());
		System.out.println("方法参数:"+joinPoint.getArgs());
		System.out.println("staticPart:"+ joinPoint.getStaticPart().toShortString());
		System.out.println("kind:"+joinPoint.getKind());
		System.out.println("sourceLocation:"+joinPoint.getSourceLocation());
		Object object = joinPoint.proceed();// 执行该方法
		System.out.println("退出方法");
		return object;
	}

}
3.applicationContext.xml配置

<?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"
	   xmlns:tx="http://www.springframework.org/schema/tx"
	   xsi:schemaLocation="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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
	<context:component-scan base-package="cn.slimsmart.spring.demo" />
	 <!-- 打开aop 注解 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
	
</beans>
4.单元测试类
package cn.slimsmart.spring.demo;

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 cn.slimsmart.spring.demo.aop.UserService;

@RunWith(SpringJUnit4ClassRunner.class)//让junit工作在spring环境中
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class SpringTest{
	
	@Autowired
	UserService userService;
	
	@Test
	public void testStart(){
		System.out.println("启动服务");
		userService.delete("abc123");
		System.out.println("====================");
		userService.update("aaa");
	}

}

运行结果:执行update抛异常:/ by zero

启动服务
进入环绕通知
目标类名称:cn.slimsmart.spring.demo.aop.UserServiceImpl
方法名称:delete
方法参数:[Ljava.lang.Object;@2de1c3f9
staticPart:execution(UserServiceImpl.delete(..))
kind:method-execution
sourceLocation:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@6ed745c2
前置通知
--------delete
退出方法
最终通知
后置通知
====================
进入环绕通知
目标类名称:cn.slimsmart.spring.demo.aop.UserServiceImpl
方法名称:update
方法参数:[Ljava.lang.Object;@1d370b4d
staticPart:execution(UserServiceImpl.update(..))
kind:method-execution
sourceLocation:org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint$SourceLocationImpl@8c6fb37
前置通知
--------update
最终通知
异常通知
注:pom.xml引入的jar包

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>cn.slimsmart.spring.demo</groupId>
	<artifactId>spring-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.1.4.RELEASE</version>
		</dependency>
		<!-- <dependency> -->
		<!-- <groupId>org.springframework</groupId> -->
		<!-- <artifactId>spring-tx</artifactId> -->
		<!-- <version>4.1.4.RELEASE</version> -->
		<!-- </dependency> -->
		<!-- <dependency> -->
		<!-- <groupId>org.springframework</groupId> -->
		<!-- <artifactId>spring-jdbc</artifactId> -->
		<!-- <version>4.1.4.RELEASE</version> -->
		<!-- </dependency> -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.1.4.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.5.4</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.4</version>
		</dependency>

		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>3.1</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib-nodep</artifactId>
			<version>3.1</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>

	</dependencies>
</project>

若不使用注解的方式,使用schema xml配置(也可以基于spring接口方式实现)的方式,如下参考:

 <aop:config>
        <aop:aspect id="businessAspect" ref="testInterceptor">
            <!-- 配置指定切入的对象 -->
            <aop:pointcut id="point_cut" expression="execution(* cn.slimsmart.spring.demo.aop.UserServiceImpl.*(..))" />
            <!-- 前置通知 -->
            <aop:before method="doBefore" pointcut-ref="point_cut" />
            <!-- 后置通知 returning指定返回参数 -->
            <aop:after-returning method="doAfter"
                pointcut-ref="point_cut" returning="result" />
            <aop:around method="doAround" pointcut-ref="point_cut"/>
            <aop:after-throwing method="doThrow" pointcut-ref="point_cut" throwing="e"/>
        </aop:aspect>
    </aop:config>

你可能感兴趣的:(spring)