关闭

spring AspectJ aop学习

228人阅读 评论(0) 收藏 举报

 

使用spring注解的方式实现AOP

 

AOP(Aspect Oriented Programming)面向切面编程

AspectJ是一个基于JAVA语言的AOP框架(编译时增强的AOP框架),提供了强大的AOP功能。

spring的AOP与AspectJ进行了很好的集成,spring使用AspectJ实现动态代理的。
 

先说明一个简单的例子:

 

1、定义一个target接口 

package hb.aop.easy;

public interface IAction {
	public void execute();
}
 
2、target接口的实现类
package hb.aop.easy;

public class ActionImp implements IAction {
	public void execute() {
		System.out.println("do action");
	}
}
 
3、定义一个“切面”类,即在target方法拦截后需要的动作
package hb.aop.easy;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AspectJEasy {

	@Before("execution(* hb.aop.easy.*Imp.*(..))")
	public void beforeAction(){
		System.out.println("简单AOP测试——before");
	}
}
 4、将定义好的类交给spring容器管理
<?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: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-2.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

	<aop:aspectj-autoproxy />
	<!--使用注解的方式AOP注入-->
	<bean
		class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />

	<bean id="iaction" class="hb.aop.easy.ActionImp" />
	<!-- 切面类交由Spring容器管理,spring会实现指定条件的aop拦截的 -->
	<bean id="aop" class="hb.aop.easy.AspectJEasy" />

</beans>

 5、测试结果

package hb.aop.easy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Test {

	public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("AplicationContext.xml");
//通过spring容器获取的对象类型应该强制转为接口,而不是具体的实现类,因为动态代理也是由接口完成的
		IAction action = (IAction)ctx.getBean("iaction");
		action.execute();
	}

}

 备注:spring容器获取的对象如果强制转为具体的实现类,会报错的

 

上面的例子很简单,很容易的就实现了AOP,对某个方法的拦截。前面的例子只是说明了在具体的方法前执行拦截,如果我想在方法执行完之后实现拦截呢?AspectJ的advice提供了下面几种方式:

1、前置通知

2、返回后通知

3、后通知

4、抛出通知

5、环绕通知

 

还是举个例子,按照上面的步骤

1、定义接口

package hb.aop.dao;

public interface Person {

	public void insert();
	
	public void update(String name);
	
	public String getPerson(Integer id);
	
	public void exception();
}

 2、接口的实现

package hb.aop.dao.imp;

import hb.aop.dao.Person;

public class PersonImp implements Person {

	public void insert() {
		System.out.println("insert");
	}

	public void update(String name) {
		System.out.println("update");
	}

	public String getPerson(Integer id) {
		System.out.println("getPerson");
		return "xxxx";
	}

	public void exception() {
		throw new RuntimeException("my exception");
	}

}

 3、定义切面

package hb.aop.aspectj;

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;

@Aspect
public class Aop {

	@Pointcut("execution(* hb.aop.dao.imp.*.*(..))")
	private void hh(){}
	
	@Before("execution(* hb.aop.dao.imp.*.*(..))")
	public void myBefore()
	{
		System.out.println("前置通知");
	}
	
	@After("execution(* hb.aop.dao.imp.*.*(..))")
	public void myAfter(){
		System.out.println("最终通知");
	}
	
	@AfterReturning("execution(* hb.aop.dao.imp.*.*(..))")
	public void myAfterReturning(){
		System.out.println("后置通知");
	}
	
	@AfterThrowing("execution(* hb.aop.dao.imp.*.*(..))")
	public void myAfterThrowing(){
		System.out.println("例外通知");
	}
	
	//关于环绕通知是固定的格式
	@Around("execution(* hb.aop.dao.imp.*.*(..))")
	public Object doBasicProfiling(ProceedingJoinPoint pjp)throws Throwable{
		System.out.println("环绕通知前");
		Object result = pjp.proceed();
		System.out.println("环绕通知后");
		return result;
	}
	
	//////////////////添加参数//////////////////////////
	/*
	 * @Pointcut("execution(* hb.dao.imp.*.*(..))")
	 * 要求切入点的方法中有且只有一个参数,而且类型是字符串的才会被拦截
	 */
	@Before("execution(* hb.aop.dao.imp.*.*(..)) && args(name)")
	public void myBefore(String name)
	{
		System.out.println("前置通知 : " + name);
	}
	
	@AfterReturning(pointcut="execution(* hb.aop.dao.imp.*.*(..))",returning="result")
	public void myAfterReturning(String result){
		System.out.println("后置通知:"+result);
	}
	
	@AfterThrowing(pointcut="execution(* hb.aop.dao.imp.*.*(..))",throwing="exceptionName")
	public void myAfterThrowing(Exception exceptionName){
		System.out.println("例外通知:"+exceptionName);
//		exceptionName.printStackTrace();
	}
	
}

 4、配置文件

<?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: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-2.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

	<aop:aspectj-autoproxy />
	<!--使用注解的方式AOP注入-->
	<bean
		class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />

	<bean id="aop1" class="hb.aop.aspectj.Aop" />
	<bean id="iperson" class="hb.aop.dao.imp.PersonImp" />
	
	

</beans>

 5、测试

package hb.aop.test;



import hb.aop.dao.Person;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Demo1 {

	public static void main(String[] args) {
		
		ApplicationContext ctx = new FileSystemXmlApplicationContext("AplicationContext.xml");
		Person aopDao1 = (Person)ctx.getBean("iperson");

		//测试不带任何参数的aop
//		aopDao1.insert();
		
		//测试传入参数的aop
		aopDao1.update("参数测试");
		
		//测试得到返回结果的aop
//		aopDao1.getPerson(3);
		
		//测试捕获异常的aop
//		aopDao1.exception();
	}
}

 

上面的例子似乎比较满意了,但是如果切面对象的内容需要改,那么岂不整个切面内的所有方法都需要改,这个肯定是不合理的,因此又引入了Pointcut这个概念

 

1、定义一个pointcut

package hb.aop.pointcut;

import org.aspectj.lang.annotation.Pointcut;

public class MyPointCut {
	
	@Pointcut("execution(* hb.aop.dao.imp.*.*(..))")
	public void hh(){
	}
}

备注:pointcut定义方法必须是void,并且方法内容为空,不做任何实现

 

 2、调用定义好的pointcut

package hb.aop.aspectj;

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;

@Aspect
public class Aop {

//	@Pointcut("execution(* hb.aop.dao.imp.*.*(..))")
//	private void hh(){}
	
	@Before("hb.aop.pointcut.MyPointCut.hh()")
	public void myBefore()
	{
		System.out.println("前置通知");
	}
	
	@After("hb.aop.pointcut.MyPointCut.hh()")
	public void myAfter(){
		System.out.println("最终通知");
	}
	
	@AfterReturning("hb.aop.pointcut.MyPointCut.hh()")
	public void myAfterReturning(){
		System.out.println("后置通知");
	}
	
	@AfterThrowing("hb.aop.pointcut.MyPointCut.hh()")
	public void myAfterThrowing(){
		System.out.println("例外通知");
	}
	
	//关于环绕通知是固定的格式
	@Around("hb.aop.pointcut.MyPointCut.hh()")
	public Object doBasicProfiling(ProceedingJoinPoint pjp)throws Throwable{
		System.out.println("环绕通知前");
		Object result = pjp.proceed();
		System.out.println("环绕通知后");
		return result;
	}
	
	//////////////////添加参数//////////////////////////
	/*
	 * @Pointcut("execution(* hb.dao.imp.*.*(..))")
	 * 要求切入点的方法中有且只有一个参数,而且类型是字符串的才会被拦截
	 */
	@Before("hb.aop.pointcut.MyPointCut.hh() && args(name)")
	public void myBefore(String name)
	{
		System.out.println("前置通知 : " + name);
	}
	
	@AfterReturning(pointcut="hb.aop.pointcut.MyPointCut.hh()",returning="result")
	public void myAfterReturning(String result){
		System.out.println("后置通知:"+result);
	}
	
	@AfterThrowing(pointcut="hb.aop.pointcut.MyPointCut.hh()",throwing="exceptionName")
	public void myAfterThrowing(Exception exceptionName){
		System.out.println("例外通知:"+exceptionName);
//		exceptionName.printStackTrace();
	}
	
}

 备注:使用方法就想java调用方法一样,hb.aop.pointcut.MyPointCut是具体的类,hh()是该类的方法,也是pointcut的名称,这样就能够找到对应的aop过滤条件了

 

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:283134次
    • 积分:8462
    • 等级:
    • 排名:第2297名
    • 原创:1096篇
    • 转载:14篇
    • 译文:0篇
    • 评论:4条
    最新评论