Spring AOP 使用摘要

4 篇文章 0 订阅

一、准备:

  1. 引入spring 4.0版本基础jar包
  2. 使用aop需额外引入aspectj支持及cglib代理支持
        <dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.0</version>
		</dependency>
		<dependency>
			<groupId>aopalliance</groupId>
			<artifactId>aopalliance</artifactId>
			<version>1.0</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib-nodep</artifactId>
			<version>2.2.2</version>
		</dependency>

3、在spring配置文件中添加对aop注解的支持

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" 
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="
           http://www.springframework.org/schema/aop     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       ">

<!-- 启动@aspectj的自动代理支持-->
	<aop:aspectj-autoproxy /> 

</beans>

上述非完整配置文件,若aop标签报错,请检查scheme中是否包含Aop支持

二、编码

1、编写一个java bean,配置成spring bean


import org.springframework.stereotype.Component;

import cn.com.guo.annotation.AopJoinPointTest;

@Component
public class Kingnight {

	private String name;
	private String age;
	
	public Kingnight() {
		this.age = "88";
		this.name = "king";
	}
	
	public void sayHello(){
		System.out.println("My name is " + name + "!");
		System.out.println("My age is " + age + "!");
	}
	
	@AopJoinPointTest(name="Kingnight:say good bye")
	public void sayGoodbye(){
		System.out.println("Nice to meeting you! Good bye!");
	}
	
}

2、切面编写

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class KingnightAopTest {

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Pointcut("execution(* cn.com.guo.beans.Kingnight.sayHello())")
	public void kingnightJoinPoint(){
	}
	
	@After(value="kingnightJoinPoint()")
	public void doAfter(){
		logger.info("KingnightAopTest============>>");
	}
	
	@Before("within(@cn.com.guo.annotation.AopJoinPointTest *)")
	public void doBefore(){
		System.out.println("Fight well and often!s");
	}
	
}

@Pointcut定义横切关注点,在增强实现(advice)中可引入其定义的关注点,以将advice以给定方式织入对应连接点中。

@After、@Before为增强实现,可通过:1>@Pointcut定义的切点;2>AspectJ指示器 找到对应的切点,并将方法织入其中。

上例中within表达式指定使用@AopJoinPointTest 自定义注解的方法,自定义注解代码:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AopJoinPointTest {

	/**
	 * 引入说明
	 * @return
	 */
	String name() default "";
	
}

3、调用(我在spring Controller中调用,未编写Junit测试):

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import cn.com.guo.beans.Kingnight;

/**
 * 测试spring配置
 * @author GuoZhinan
 */
@Controller
@ResponseBody
public class BaseController {

	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	private Kingnight kingnight;
	
	@RequestMapping("/*.do")
	public void doTest(HttpServletRequest req, HttpServletResponse resp){
		logger.info("--start--");
		kingnight.sayHello();
		logger.info("--the work is over--");
		kingnight.sayGoodbye();
	}
	
}

测试结果:

14:00:05.976 [http-8080-2] INFO  cn.com.guo.controller.BaseController - --start--
My name is king!
My age is 88!
14:00:06.251 [http-8080-2] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'kingnightAopTest'
14:00:06.252 [http-8080-2] INFO  cn.com.guo.aop.KingnightAopTest - KingnightAopTest============>>
14:00:06.252 [http-8080-2] INFO  cn.com.guo.controller.BaseController - --the work is over--
Nice to meeting you! Good bye!

三、Api整理

1、@Pointcut 定义横切关注点

        (1) 类型匹配语法:

          *:匹配任何数量字符;

         ..:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。

         +:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

java.lang.String    匹配String类型  

java.*.String       匹配java包下的任何“一级子包”下的String类型,如匹配java.lang.String,但不匹配java.lang.XXX.String  

java..*             匹配java包及任何子包下的任何类型, 如匹配java.lang.String、java.lang.annotation.Annotation  

java.lang.*ing      匹配任何java.lang包下的以ing结尾的类型

java.lang.Number+   匹配java.lang包下的任何Number的自类型,如匹配java.lang.Integer,也匹配java.math.BigInteger 

注意:使用 且(&&)、或(||)、非(!)来组合切入点表达式       

(2) Spring兼容的AspectJ指示器:

AspectJ指示器描述
args()限定连接点匹配参数为指定类型的执行方法
@args()限定连接点匹配参数由指定注解标注的执行方法
execution()用于匹配连接点执行的方法
within()限定匹配连接点指定的类型
@within()限定匹配连接点指定注解所标注的类型(当使用Spring AOP时,方法定义在指定的注解所标注的类里)
@annotation限定匹配带有特定注解的连接点
target()限定连接点匹配目标对象为指定类型的类
this()限定连接点匹配AOP代理的类型bean引用为指定类型的类
  
  

以上是spring Aop兼容的AspectJ指示器(若有错漏,还请指正),若要使用AspectJ其它指示器,需使用spring集成AspectJ。

2、增强实现定义

Advice类型定义
@Before前置通知:在切入点运行前执行,不会影响切入点的逻辑
@After后置通知:在切入点正常运行结束后执行,如果切入点抛出异常,则在抛出异常前执行
@AfterThrowing异常通知:在切入点抛出异常前执行,如果切入点正常运行(未抛出异常),则不执行
@AfterReturning返回通知:在切入点正常运行结束后执行,如果切入点抛出异常,则不执行
@Around环绕通知:在切入点执行前后自定义一些操作。需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行

 

 

 

 

 

 

 

(1)JoinPoint 

用于获取连接点的相关信息

import org.aspectj.lang.reflect.SourceLocation;  
public interface JoinPoint {  
   String toString();         //连接点所在位置的相关信息  
   String toShortString();     //连接点所在位置的简短相关信息  
   String toLongString();     //连接点所在位置的全部相关信息  
   Object getThis();         //返回AOP代理对象  
   Object getTarget();       //返回目标对象  
   Object[] getArgs();       //返回被通知方法参数列表  
   Signature getSignature();  //返回当前连接点签名  
   SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置  
   String getKind();        //连接点类型  
   StaticPart getStaticPart(); //返回连接点静态部分  
  } 

(2)ProceedingJoinPoint

用于在环绕通知中执行被通知方法(下为接口源码):

package org.aspectj.lang;

import org.aspectj.runtime.internal.AroundClosure;

public interface ProceedingJoinPoint extends JoinPoint {

    void set$AroundClosure(AroundClosure arc);

    public Object proceed() throws Throwable;

    public Object proceed(Object[] args) throws Throwable;

}

(3)在advice中获取连接点方法传入参数

可使用args指示器将参数自动传递给方法:

@Before(value="execution(* test(*)) && args(param)", argNames="param")  
public void doBefore(String param) 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值