`
weiwu2012
  • 浏览: 435 次
  • 性别: Icon_minigender_1
  • 来自: 南京
文章分类
社区版块
存档分类
最新评论

spring xml配置及annotation注解 详解

阅读更多


最近用到了spring的aop,对aop(面向切面编程)记忆有了新的加深,鉴于方便别人也方便自己找资料,特地做了小demo来展示一下xml配置和注解实现的aop,展示了各种通知,并且在各种通知里面获得各种值,这里要提一下,用xml配置做前置通知获得参数的时候,出现过一个问题::0 formal unbound in pointcut ,这里很搞了一会儿,网上也找了各种资料,实在感叹,盲目转帖,各种不做自己判断真是坑爹,基本十有八九都是同样的答案,关键是烂答案,后来不断尝试,终于解决问题,下面会奉上解决方案 



spring-aop-xml.xml配置


复制代码

1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <beans xmlns="http://www.springframework.org/schema/beans"
4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5     xmlns:context="http://www.springframework.org/schema/context"
6     xmlns:aop="http://www.springframework.org/schema/aop"
7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
8         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
9         http://www.springframework.org/schema/context 
10         http://www.springframework.org/schema/context/spring-context-2.5.xsd
11         http://www.springframework.org/schema/aop
12         http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
13
14    
15    
16     <!-- 要被拦截的类定义 -->
17     <bean id="aopService" class="com.pis.aop.AopService"/>
18     <!-- 被拦截类aopService的拦截类 -->   
19     <bean id="serviceInterceptor"  class="com.pis.aop.ServiceInterceptor"/>   
20        
21     <aop:config>
22         <!-- 声明proxyService为一个切面 也就是拦截类-->
23        
24         <aop:aspect id="asp" ref="serviceInterceptor">
25        
26             <!-- pointcut切入点 即对目标的哪些方法进行拦截  expression是拦截表达式
27             最常用的是  execution(*  com.pis.aop.*.*(..))
28             对所有方法进行拦截 第一个"*"号代表返回类型 第二个"*"代表com.pis.aop下面所有类
29             第三个"*"代表所有方法 "(..)代表所有参数"-->
30        
31             <aop:pointcut id="target" expression="execution(String  com.pis.aop.AopService.*(String)) "/>
32            
33             <aop:pointcut id="target_1" expression="execution(*  com.pis.aop.*.*(..))"/>
34            
35            
36            
37             <!-- 设定前置通知 并且获得参数值  实践证明pointcut-ref注入target获得参数是会报:0 formal unbound in pointcut的,而直接写切入点表达式是可以的
38                 在这里纠结半天,事实也证明arg-names="str"是没有用的  还是直接写切入点并指定参数最有效 这里的str要对应切面和被拦截类的方法的参数名
39             -->
40             <aop:before method="before" pointcut="execution(String  com.pis.aop.AopService.*(String)) and args(str)" />
41             
42             
43             
44             <!-- 设定后置通知 -->
45             <aop:after-returning method="afterReturn" pointcut-ref="target" returning="result"/>
46            
47             <!-- 设定环绕通知 -->
48             <aop:around method="around" pointcut-ref="target"/>
49            
50            
51             <!-- 设定最终通知 -->
52             <aop:after method="after" pointcut-ref="target"/>
53            
54            
55             <!-- 设定异常通知 -->
56             <aop:after-throwing method="afterThrowing" pointcut-ref="target_1"  throwing="e"/>
57            
58            
59         </aop:aspect>
60     </aop:config>
61    
62 </beans>

复制代码





AopService.java,即要被拦截的类
复制代码

1 package com.pis.aop;
2
3 import org.springframework.stereotype.Component;
4
5
6 @Component("aopService")
7 public class AopService {
8
9    
10    
11     //用来验证前置通知获取参数
12     public String execute(String str){
13         System.out.println("终于轮到我execute方法执行了");
14         try {
15             throw new Exception("可爱的异常");
16         } catch (Exception e) {
17 //            System.out.println(e.getMessage());
18         } finally {
19 //            System.out.println("finally执行");
20         }
21         return "result";
22     }
23    
24    
25     public void excp() throws Exception{
26         throw new Exception("可爱的异常");
27     }
28    
29 }

复制代码



ServiceInterceptor.java 切面类  也就是拦截类(官方名词:代理类)


复制代码

1 package com.pis.aop;
2
3 import org.aspectj.lang.ProceedingJoinPoint;
4 import org.aspectj.lang.annotation.After;
5 import org.aspectj.lang.annotation.AfterReturning;
6 import org.aspectj.lang.annotation.AfterThrowing;
7 import org.aspectj.lang.annotation.Around;
8 import org.aspectj.lang.annotation.Aspect;
9 import org.aspectj.lang.annotation.Before;
10 import org.aspectj.lang.annotation.Pointcut;
11 import org.springframework.stereotype.Component;
12
13
14 //定义切面  也就是拦截类
15 @Component("serviceInterceptor")
16 @Aspect
17 public class ServiceInterceptor {
18
19     //定义一个切入点 拦截的是execute方法
20     @Pointcut("execution(String  com.pis.aop.AopService.*(String))")
21     public void pointcut(){}
22    
23     //定义前置通知
24     @Before("pointcut() && args(str)")
25     public void before(String str){
26         System.out.println("***进入前置通知,获取参数:***");
27     }
28    
29     //这里的returning的值result必须和afterReturn的参数一致  pointcut引入写法较其他方法有所不同
30     @AfterReturning(pointcut="pointcut()", returning="result")
31     public void afterReturn(String result){
32         System.out.println("***进入后置通知,获取返回结果:"+result+"***");
33     }
34    
35     //定义最终通知
36     @After("pointcut()")
37     public void after(){
38         System.out.println("***进入最终通知***");
39     }
40    
41     //自定义了一个切入点,并获得异常信息
42     @AfterThrowing(pointcut="execution(*  com.pis.aop.*.*(..))", throwing = "e")
43     public void afterThrowing(Exception e){
44         System.out.println("***进入例外通知,获得异常信息:"+e+"***");
45     }
46    
47     //定义环绕通知
48     @Around("pointcut()")
49     public Object around(ProceedingJoinPoint pjp){
50         Object obj=null;
51         System.out.println("***进入环绕通知***");
52         try {
53             obj = pjp.proceed();//此处返回的是拦截的方法的返回值,如果不执行此方法,则不会执行被拦截的方法,利用环绕通知可以很好的做权限管理
54         } catch (Throwable e) {
55             e.printStackTrace();
56         }
57         System.out.println("***退出环绕通知***");
58         return obj;
59     }
60 }

复制代码





AopTest.java  专门来测试aop的类,junit来写的,直接改成main方法亦可以
复制代码

1 package com.pis.aop;
2
3 import org.junit.Before;
4 import org.junit.Test;
5 import org.springframework.context.ApplicationContext;
6 import org.springframework.context.support.ClassPathXmlApplicationContext;
7
8
9
10 public class AopTest {
11     ApplicationContext atx = null;
12     AopService aopService = null;
13     @Before
14     public void before(){
15         atx = new ClassPathXmlApplicationContext("/spring/spring-aop-xml.xml");
16 //        atx = new ClassPathXmlApplicationContext("/spring/spring-aop-annotation.xml");
17         aopService = (AopService)atx.getBean("aopService");
18     }
19    
20    
21    
22    
23     //前置通知
24     @Test
25     public void testExecute(){
26         aopService.execute("param");   
27     }
28    
29     //例外通知
30     @Test
31     public void testExcp() throws Exception{
32         aopService.excp();
33     }
34    
35    
36 }

复制代码



注解版:

spring-aop-annotation.xml  对,零配置 ,就是这么简单
复制代码

1 <?xml version="1.0" encoding="UTF-8"?>
2
3 <beans xmlns="http://www.springframework.org/schema/beans"
4     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5     xmlns:context="http://www.springframework.org/schema/context"
6     xmlns:aop="http://www.springframework.org/schema/aop"
7     xsi:schemaLocation="http://www.springframework.org/schema/beans 
8         http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
9         http://www.springframework.org/schema/context 
10         http://www.springframework.org/schema/context/spring-context-2.5.xsd
11         http://www.springframework.org/schema/aop
12         http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
13
14
15     <aop:aspectj-autoproxy/>  <!-- 开启自动扫描注解 -->
16
17     <context:component-scan base-package="com.pis.aop"/>    <!-- 指定在哪个包范围扫描 -->   
18
19
20    
21 </beans>

复制代码



被拦截类和切面与上面的一样,我是xml配置测试完了之后,直接在原有代码上面加的注解而已



AopTest.java  注解版的就是切换了一个xml文件而已,从spring-aop-xml.xml配置换成了spring-aop-annotation.xml配置
复制代码

1 package com.pis.aop;
2
3 import org.junit.Before;
4 import org.junit.Test;
5 import org.springframework.context.ApplicationContext;
6 import org.springframework.context.support.ClassPathXmlApplicationContext;
7
8
9
10 public class AopTest {
11     ApplicationContext atx = null;
12     AopService aopService = null;
13     @Before
14     public void before(){
15 //        atx = new ClassPathXmlApplicationContext("/spring/spring-aop-xml.xml");
16         atx = new ClassPathXmlApplicationContext("/spring/spring-aop-annotation.xml");
17         aopService = (AopService)atx.getBean("aopService");
18     }
19    
20    
21    
22    
23     //前置通知
24     @Test
25     public void testExecute(){
26         aopService.execute("param");   
27     }
28    
29     //例外通知
30     @Test
31     public void testExcp() throws Exception{
32         aopService.excp();
33     }
34    
35    
36 }

复制代码







ok!上面的两种配置都已完成,测试不同版本的时候,只需切换读取的配置文件即可,做就做全,这里给出了前置通知获取参数,后置通知获取返回值,例外通知获得异常的例子,特别是前置通知获得参数闹了好久,两种版本的获值均已实现,下面给出截图,如有问题,欢迎拍砖,



这里是执行testExecute的结果,从这里可以很清晰的看到各个通知的执行顺序     前置通知-环绕通知-方法-后置通知-环绕通知-最终通知(对应的是finally),例外通知只能是连接点出异常的时候才会有,所有我特地写了两个测试方法,testExcp就是专门测试例外通知的



testExecute结果图









testExcp结果图    可以看见异常被拦截了





最后要提下,环绕通知中可以做很多事,比如权限拦截,日志拦截等,可以看切面的拦截方法around就知道,另外附上自己对各个aop名称的理解

aspect:切面    拦截类

joinpoint:  连接点  被拦截的方法

advice:  通知  拦截到方法之后要执行的各种操作,比如各种通知

cutpoint: 切入点  对哪些连接点进行的定义,也就是对那些被拦截方法或方法的集合的定义

分享到:
评论

相关推荐

    Spring Annotation (注解)详解

    5. **传统XML配置与注解配置** - 在没有注解之前,我们需要在XML配置文件中显式定义Bean及它们的依赖。例如,`beans.xml`文件中,我们需要声明每个Bean以及它们之间的依赖关系。而使用注解后,这些配置可以直接写在...

    详解Spring_3.0基于Annotation的依赖注入实现

    #### 注解详解 - **`@Repository`**:此注解主要用于标记数据访问层(Data Access Object, DAO)的类,使其成为Spring容器管理的对象。除了将类标识为Bean外,`@Repository`还提供了一种机制来处理数据库访问异常,...

    详解 Spring 3.0 基于 Annotation 的依赖注入实现

    - 通过 `&lt;context:component-scan&gt;` 标签,可以在 XML 配置文件中指定基础包,让 Spring 自动扫描这些包及其子包下的类,寻找带有特定注解的类,将它们注册为 Bean。例如: ```xml ``` 3. **...

    spring 的Annotation方式

    ### Spring的Annotation方式详解 #### 引言 随着Spring框架的发展,其依赖注入(DI)机制也经历了从XML配置向注解驱动的重大转变。自Spring 3.0版本起,框架引入了一系列注解来简化依赖配置,使得开发人员能够在不...

    spring配置详解

    除了XML配置,Spring 3.0以后引入了Java配置,通过`@Configuration`注解的类来替代XML配置,使得配置更简洁且易于测试。 以上只是`applicationContext.xml`配置文件中一部分常见的知识点,实际应用中还有更多高级...

    spring注解详解

    Spring框架的注解详解 Spring框架自2.5版本开始引入了注解配置,使得开发者可以更加便捷地管理Bean和装配Bean,减少了XML配置的工作量。注解配置的优势在于其与Java代码的紧密集成,利用Java的反射机制,提高了开发...

    Spring注解详解

    在Java Spring框架中,注解(Annotation)是配置的核心元素之一,它们极大地简化了XML配置,使得代码更加简洁,更具可读性。本篇将详细解析Spring中的主要注解及其用法。 一、注解说明 1. 使用简化配置:Spring...

    Spring Boot 整合 Mybatis Annotation 注解的完整 Web 案例

    Spring Boot 和 Mybatis 的整合使得开发过程更加简洁高效,特别是当使用注解进行配置时,可以避免大量的 XML 配置文件,提高开发效率。在这个案例中,我们将探讨如何在 Spring Boot 项目中集成 Mybatis 并使用注解...

    Spring 事务配置详解(多种配置方法)

    本文将详细解析Spring事务配置的多种方法,包括XML配置和注解方式。 首先,理解Spring事务配置的基本组件至关重要。这些组件主要包括: 1. **DataSource**:数据源,它是连接数据库的桥梁,负责管理与数据库的连接...

    spring注解

    Spring 注解详解 Spring 注解是 Spring 框架中的一种强大功能,它允许开发者使用注解来配置和管理 Bean 对象。本文将详细讲解 Spring 注解的含义、类型、使用方法和相关配置。 注册注解处理器 在 Spring 中,需要...

    Spring 配置文件XML头部文件模板实例详解

    以上就是关于Spring配置文件XML头部文件模板的实例详解,包括了普通配置文件模板和添加注解后的格式模板。希望这些内容能帮助到需要使用Spring配置的开发者,让他们更加熟悉如何利用配置文件来管理和优化Spring应用...

    详解spring applicationContext.xml 配置文件

    7. `&lt;cache&gt;`:Spring的缓存抽象允许通过注解或XML配置来管理缓存。例如,`&lt;cache:annotation-driven&gt;`可以启用基于注解的缓存管理。 此外,`xsi:schemaLocation`定义了每个命名空间对应的schema位置,确保解析器...

    spring事务配置详解

    Spring 3.0以后,可以使用Java配置来替代XML配置,实现方式类似,但更简洁。例如: ```java @Configuration @EnableTransactionManagement public class AppConfig { @Bean public ...

    spring注解使用详解

    ### Spring注解使用详解 #### 引言 随着软件开发技术的发展,框架的引入极大地提升了开发效率和代码的可维护性。Spring作为Java领域最受欢迎的企业级应用开发框架之一,其强大的功能之一便是对注解的支持。注解在...

    Spring_aop_annotation.zip

    《Spring AOP注解实践详解》 在Java开发领域,Spring框架因其强大的功能和灵活性而备受推崇,其中AOP(面向切面编程)是其重要特性之一。本实践项目以"Spring_aop_annotation.zip"为载体,展示了如何利用注解在...

    spring4注解

    ### Spring4 注解详解 #### 一、背景与概述 在Spring框架的早期版本中,主要依赖XML配置文件来进行依赖注入和其他配置管理。随着技术的发展和应用需求的变化,这种配置方式逐渐显得繁琐且不易维护。为了解决这一...

    SpringMVC 原理及配置详解Demo

    在"Spring MVC原理及配置详解.txt"和"SpringMVC"文件中,可能包含了更详细的原理介绍、配置示例和实际的代码样例,供学习者深入理解SpringMVC的运作机制和实践应用。 通过以上内容,你可以了解到SpringMVC的基本...

Global site tag (gtag.js) - Google Analytics