spring AspectJ aop学习

原创 2013年12月04日 09:56:11

 

使用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过滤条件了

 

 

spring学习--面向切面编程AOP和AspectJ

—AOP(面向切面编程)1.代理模式代理模式是指,为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作...

spring 学习笔记 使用aspectj开发aop

1.添加类库:aspectjrt.jar和aspectjweaver.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar com.s...
  • Ace_Yu
  • Ace_Yu
  • 2013年02月28日 10:29
  • 928

Spring学习4-面向切面(AOP)之aspectj注解方式

一、简介    1、AOP用在哪些方面:AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制,异常处理等,封装起来,便于减少系统的重复代码,降低模块间的耦...

学习《spring 3.x企业应用开发实战》之基于@AspectJ和Schema的AOP

前言: 上一章中已经介绍,Spring中定义一个切面是比较麻烦的,需要实现专门的接口,并进行一些较为复杂的配置。经过改进,如今Spring AOP已经焕然一新,用户可以使用@AspectJ注解非常...

spring学习之使用AspectJ实现AOP

Hello.java package com.aspect.service; public interface Hello { public void foo(); public i...

Spring学习笔记--Spring AOP(基于@AspectJ)

Spring AOP默认是使用j2se的动态代理为AOP代理, 这一点可以应用于任何实现接口的类, 但是在一个没有实现任何接口的类情况下, 由于j2se的动态代理是不支持没有实现接口的类的, 所以Sp...

Spring的AOP依赖包-AspectJ

  • 2017年03月31日 12:28
  • 2.03MB
  • 下载

SSH(1) AOP原理及相关概念学习+AspectJ注解方式配置spring AOP

AOP(Aspect Oriented Programming),是面向切面编程的技术。AOP基于IoC基础,是对OOP的有益补充。     AOP之所以能得到广泛应用,主要是因为它将应用系...

SSH深度历险(十) AOP原理及相关概念学习+AspectJ注解方式配置spring AOP

使用AOP,我们要注意关注横切性的功能,即抽象出独立服务,进行模块化使我们以前习惯性的纵向思维的方法再改变,注意横向思考问题的方式,我们结合现在的系统可以把判断文本框一些了的验证、日志的记录、事务的开...
  • lishehe
  • lishehe
  • 2014年07月06日 12:57
  • 3611
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:spring AspectJ aop学习
举报原因:
原因补充:

(最多只允许输入30个字)