spring之aop编程——基于注解、xml配置文件方式

AOP(Aspect Oriented Programming),是面向切面编程的技术。AOP基于IoC基础,是对OOP的有益补充。spring中AOP的配置方式有2种方式:xml配置和AspectJ注解方式。

一、xml配置的方式:

1、service接口和服务类:
package cn.edu.nuc.SpringTest.service;


public interface DemoService {
public String sayHello(String name) ;
}




package cn.edu.nuc.SpringTest.service.impl;


import org.springframework.stereotype.Service;
import cn.edu.nuc.SpringTest.common.anno.Permission;
import cn.edu.nuc.SpringTest.service.DemoService;


@Service  
public class DemoServiceImpl implements DemoService{

@Permission(value="no")
public String sayHello(String name) {
System.out.println("hello word.........."+name);
return "返回值";
}
}


2、切面类开发:
package cn.edu.nuc.SpringTest.interceptor;


import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import cn.edu.nuc.SpringTest.common.anno.Permission;


public class MyInterceptor1 {
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知进入方法----");
Object object=pjp.proceed();
System.out.println("环绕通知退出方法------");
return object;
}

//后置通知(不需要获取返回值)
public void doAfterReturning(JoinPoint jp,String name,Object rvt){
System.out.println("后置通知,参数:"+name);
System.out.println("后置返回:"+rvt);
}

public void doAfterThrowing(JoinPoint jp,Throwable ex){
System.out.println("例外通知~~~~~~~~~~~~~~~~~~~");
System.out.println("method " + jp.getTarget().getClass().getName()  
                + "." + jp.getSignature().getName() + " throw exception");  
        System.out.println(ex.getMessage()+ex.toString());  
}

//最终通知
public void doAfter(JoinPoint jp,String name){
        System.out.println("最终通知--------");
}

//前置通知(不需要获取输入参数)
public void doAccessCheck(JoinPoint jp){
Object[] args = jp.getArgs();
Signature signature = jp.getSignature();
MethodSignature methodSignature = (MethodSignature)signature;    
   Method targetMethod = methodSignature.getMethod();  
   if (targetMethod.isAnnotationPresent(Permission.class)) {
    Permission annotation = targetMethod.getAnnotation(Permission.class);
    System.out.println("我是anno:"+annotation.value());
   }
System.out.println("前置通知--------"+",参数:"+args[0]);
}
}


3、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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
     http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-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">
   
     <context:component-scan base-package="cn.edu.nuc.SpringTest"/>
<bean id="myInterceptor11" class="cn.edu.nuc.SpringTest.interceptor.MyInterceptor1"></bean> 

<aop:config proxy-target-class="true">
   <aop:aspect id="asp1" ref="myInterceptor11">
     <aop:pointcut expression="execution (* cn.edu.nuc.SpringTest.service..*.*(..))"  id="mycut"/>  
     <aop:before method="doAccessCheck" pointcut="execution (* cn.edu.nuc.SpringTest.service..*.*(..))" />
     <aop:after method="doAfter" pointcut="execution (* cn.edu.nuc.SpringTest.service..*.*(..)) and args(name)" />
     <aop:after-returning method="doAfterReturning" pointcut="execution (* cn.edu.nuc.SpringTest.service..*.*(..)) and args(name)" returning="rvt" />
     <aop:around method="doBasicProfiling" pointcut="execution (* cn.edu.nuc.SpringTest.service..*.*(..))" />
     <aop:after-throwing method="doAfterThrowing" pointcut-ref="mycut" throwing="ex"/>
   </aop:aspect>
</aop:config>
</beans> 


4、测试:
public class App  {
    public static void main( String[] args ) {
      String[] fileUrl = new String[]{"classpath*:applicationContext.xml"};   
         ApplicationContext appContext = new ClassPathXmlApplicationContext(fileUrl);
         
          DemoServiceImpl ser = appContext.getBean(DemoServiceImpl.class);
      ser.sayHello("刘晓111");
    }
}
注意点:
1)后置返回通知方法中,如果要获得切入点方法返回值,需要配置returning,且需要保持与后置返回通知方法的参数名一致;
2)后置异常通知方法中,如果要获得切入点方法异常,需要配置throwing,且保持与方法中异常的参数名一致;
3)在xml中,可以通过<aop:pointcut… 配置多个切入点,然后在切面类中的前置、后置、环绕、例外通知中使用不同的切入点;
4)在前置、后置、例外通知的方法中,JoinPoint要 作为第一个参数,(环绕通知使用的是ProceedingJoinPoint),通过JoinPoint 配合反射可以获得切入点的类、方法、注解等信息;(这里注意,JoinPoint 一定要放在第一个参数的位置,当JoinPoint 和切入点方法参数、切入点方法返回值、例外对象放在一起时,如果JoinPoint 不在第一个参数位置,那么spring会报一个无法绑定切入点的错误error at ::0 formal unbound in pointcut。例如:public void doAfterReturning(JoinPoint jp,String name,Object rvt)中,既有JoinPoint 也有切入点方法参数、还有切入点方法返回,JoinPoint 一定放在第一位)
5)切面类的通知方法中获取切入点方法的参数:
 1.在通知方法中,可以通过JoinPoint 获取切入点方法的所有参数;
 2.可以在xml中配置and args(name) ,name要和切入点方法参数名、通知方法的参数名一致,这样就可以在通知方法中的参数获取切入点方法的参数了;


补充:切面类是指附加功能的类,例如 MyInterceptor1 ,通知方法是切面类中,aop规定好的前置、后置...标记的方法;

切入点类,是要被切入的业务类,如DemoServiceImpl ,切入点方法是切入点类中,被切入的方法。


二、注解方式:

1、service接口和服务类:(同上)

 

2、切面类开发:

packagecn.edu.nuc.SpringTest.interceptor;

 

importjava.lang.reflect.Method;

importorg.aspectj.lang.JoinPoint;

importorg.aspectj.lang.ProceedingJoinPoint;

importorg.aspectj.lang.Signature;

importorg.aspectj.lang.annotation.After;

importorg.aspectj.lang.annotation.AfterReturning;

importorg.aspectj.lang.annotation.AfterThrowing;

importorg.aspectj.lang.annotation.Around;

importorg.aspectj.lang.annotation.Aspect;

importorg.aspectj.lang.annotation.Before;

importorg.aspectj.lang.annotation.Pointcut;

importorg.aspectj.lang.reflect.MethodSignature;

importorg.springframework.stereotype.Component;

importcn.edu.nuc.SpringTest.common.anno.Permission;

 

@Component

@Aspect

public classMyInterceptor {

 //切入点要拦截的类,声明一个切入点,切入点的名称其实是一个方法

@Pointcut("execution(* cn.edu.nuc.SpringTest.service..*.*(..))")

privatevoid anyMethod(){}

 

//声明一个切入点,切入点的名称其实是一个方法

@Pointcut(value="execution(* cn.edu.nuc.SpringTest.service..*.*(java.lang.String)) && args(name)")

privatevoid nameParameMethod(String name){}

 

@Around("anyMethod()")

publicObject doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable{

System.out.println("环绕通知进入方法");

Objectobject=pjp.proceed();

System.out.println("环绕通知退出方法");

returnobject;

}

 

//后置通知(不需要获取返回值)

//        @AfterReturning("anyMethod()")

@AfterReturning (pointcut="anyMethod()",returning="result")

publicvoid doAfterReturning(JoinPoint jp,String result){

Object[]args = jp.getArgs();

 

Objecttarget = jp.getTarget();

Signaturesignature = jp.getSignature();

MethodSignaturemethodSignature = (MethodSignature)signature;   

    Method targetMethod =methodSignature.getMethod(); 

   

    boolean b =targetMethod.isAnnotationPresent(Permission.class);

    if (b) {

           Permission perm =targetMethod.getAnnotation(Permission.class);

           String value =perm.value();

           System.out.println("@@@@@@@@@@@@@@@@@"+value);

    }

   

   

System.out.println("======="+signature.getName()+";"+jp.getThis().toString());

System.out.println("后置通知:"+args[0]+target.toString()+";返回值:"+result);

}

 

//@AfterThrowing("anyMethod()")

@AfterThrowing(pointcut="anyMethod()" ,throwing="e")

publicvoid doAfterThrowing(Exception e){

System.out.println("例外通知:");

}

 

//最终通知

@After(value="anyMethod()")

publicvoid doAfter(JoinPoint jp){

Object[]args = jp.getArgs();

   System.out.println("最终通知:================="+args[0]);

}

 

//前置通知(不需要获取输入参数)

@Before("nameParameMethod(name)")//第一个参数为切入点的名称,第二个是测试获取输入参数,此处为string类型的,参数名称与方法中的名称相同,如果不获取输入参数,可以不要

//@Before("anyMethod()")//第一个参数为切入点的名称

public void doAccessCheck(JoinPoint jp,String name){

 

System.out.println("前置通知:"+name);

}

}

 

3、配置文件:

<?xmlversion="1.0" encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns:aop="http://www.springframework.org/schema/aop"

   xmlns:context="http://www.springframework.org/schema/context"

   xmlns:tx="http://www.springframework.org/schema/tx"

   xsi:schemaLocation="http://www.springframework.org/schema/beans

     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

     http://www.springframework.org/schema/aop

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

  

        <context:component-scanbase-package="cn.edu.nuc.SpringTest"/>

  <!-- 注解方式的aop -->

 <aop:aspectj-autoproxy  proxy-target-class="true"/>

</beans>

注:需要使用<aop:aspectj-autoproxy  proxy-target-class="true"/>  开启注解aop功能,如果使用了ioc,那么一定要加上proxy-target-class="true"

 

4、测试类:(同上)

 

注意点:

1)后置返回通知方法中,如果要获得切入点方法返回值,需要在AfterReturning 注解中加上returning,且需要保持与后置返回通知方法的参数名一致

2)后置异常通知方法中,如果要获得切入点方法异常,需要在AfterThrowing注解中加上throwing,且保持与方法中异常的参数名一致

3)同样,在通知方法中,JoinPoint要 作为第一个参数,例如:public void doAccessCheck(JoinPoint jp,String name)中;

4)切面类的通知方法中获取切入点方法的参数:

 1.在通知方法中,可以通过JoinPoint 获取切入点方法的所有参数;

 2.在切面类的注解上配置andargs(name)name要和切入点方法参数名、通知方法的参数名一致,这样就可以在通知方法中的参数获取切入点方法的参数了;


pom.xml

<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.edu.nuc</groupId>
  <artifactId>SpringTest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>SpringTest</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <org.springframework.version>3.1.1.RELEASE</org.springframework.version>
  </properties>
  
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.8.1</version>
      <scope>test</scope>
    </dependency>
    
    <dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-webmvc</artifactId>
	    <version>${org.springframework.version}</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-orm</artifactId>
	    <version>${org.springframework.version}</version>
	</dependency>
	<dependency>
	    <groupId>org.springframework</groupId>
	    <artifactId>spring-test</artifactId>
	    <version>${org.springframework.version}</version>
	    <type>jar</type>
	    <scope>test</scope>
	</dependency>
	<dependency>
	    <groupId>org.aspectj</groupId>
	    <artifactId>aspectjweaver</artifactId>
	    <version>1.8.2</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-core</artifactId>
		<version>2.2.3</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.2.3</version>
	</dependency>
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-annotations</artifactId>
		<version>2.2.3</version>
	</dependency>
	
	<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>2.2</version>
	</dependency>
	
  </dependencies>

</project>


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赶路人儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值