爱程序网

实例说明spring实现aop的2种方式(注解和xml配置)

来源: 阅读:

  本文说到spring的配置,常见的有两种:注解方式和xml文件配置方式。(直接上实例,所以细节方面不会提及)

本人用的是maven项目,下面附上maven pom文件的依赖jar:

 1 <dependencies>
 2     <dependency>
 3       <groupId>junit</groupId>
 4       <artifactId>junit</artifactId>
 5       <version>3.8.1</version>
 6       <scope>test</scope>
 7     </dependency>
 8     <dependency>
 9         <groupId>org.springframework</groupId>
10         <artifactId>spring-context</artifactId>
11         <version>4.2.1.RELEASE</version>
12     </dependency>
13     <dependency>
14         <groupId>commons-logging</groupId>
15         <artifactId>commons-logging</artifactId>
16         <version>1.2</version>
17     </dependency>
18     <dependency>
19         <groupId>org.jdom</groupId>
20         <artifactId>jdom</artifactId>
21         <version>1.1.3</version>
22     </dependency>
23     <dependency>
24         <groupId>cglib</groupId>
25         <artifactId>cglib-nodep</artifactId>
26         <version>2.1_3</version>
27     </dependency>
28     <dependency>
29         <groupId>org.aspectj</groupId>
30         <artifactId>aspectjrt</artifactId>
31         <version>1.6.11</version>
32      </dependency>
33      <dependency>
34         <groupId>org.aspectj</groupId>
35         <artifactId>aspectjweaver</artifactId>
36         <version>1.6.11</version>
37      </dependency>
38   </dependencies>
maven pom.xml

 

下面图文说明我们src下的包结构:

 

上图所示 就是我们的包文件以及需要的几个类:

首先, 建立model类UserManager,代码如下:

 1 package com.wangku.spring.model;
 2 
 3 public class UserManager {
 4 
 5     private int id;
 6     private String name;
 7     private String password;
 8     
 9     public int getId() {
10         return id;
11     }
12     public void setId(int id) {
13         this.id = id;
14     }
15     public String getName() {
16         return name;
17     }
18     public void setName(String name) {
19         this.name = name;
20     }
21     public String getPassword() {
22         return password;
23     }
24     public void setPassword(String password) {
25         this.password = password;
26     }
27 
28 }
UserManagerr

 

然后, 建立一个测试service接口IUserManagerService类,代码如下:

 1 package com.wangku.spring.service;
 2 
 3 import com.wangku.spring.model.UserManager;
 4 
 5 public interface IUserManagerService {
 6 
 7     public void addUser(String userName, String password);
 8     
 9     public void updateUser(int userId, String userName, String password);
10     
11     public void deleteUser(int userId);
12     
13     public UserManager findUser(int userId);
14 }
IUserManagerService

 

接着写一个实现类UserManagerServiceImpl并实现上面的接口,代码如下:

 1 package com.wangku.spring.service.impl;
 2 
 3 import org.springframework.stereotype.Service;
 4 
 5 import com.wangku.spring.model.UserManager;
 6 import com.wangku.spring.service.IUserManagerService;
 7 
 8 @Service("manager")
 9 public class UserManagerServiceImpl implements IUserManagerService{
10 
11     public void addUser(String userName, String password) {
12         System.out.println("--------------UserManager addUser-------------");
13     }
14 
15     public void updateUser(int userId, String userName, String password) {
16         System.out.println("--------------UserManager updateUser-------------");
17     }
18 
19     public void deleteUser(int userId) {
20         System.out.println("--------------UserManger deleteUser-------------");
21     }
22 
23     public UserManager findUser(int userId) {
24         UserManager userManager = new UserManager();
25         System.out.println("--------------UserManager findUser-------------");
26         return userManager;
27     }
28 }
UserManagerServiceImpl

 

此时在spring的配置文件添加UserManagerServiceImpl的bean,代码如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 4     xmlns:context="http://www.springframework.org/schema/context"
 5     xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
 6     xmlns:jpa="http://www.springframework.org/schema/data/jpa"
 7     xsi:schemaLocation="
 8         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
 9         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
10         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
11         http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
12         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
13         http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
14         
15         <bean id="userManager" class="com.wangku.spring.service.impl.UserManagerServiceImpl" />
16 
17 </beans>
applicationContext.xml

配置好bean之后,我们建立一个测试类写测试用例测试我们的model,代码如下:

 1 import org.junit.Test;
 2 import org.springframework.context.ApplicationContext;
 3 import org.springframework.context.support.ClassPathXmlApplicationContext;
 4 
 5 import com.wangku.spring.service.IUserManagerService;
 6 
 7 public class TestUserManager {
 8 
 9     @Test
10     @SuppressWarnings("resource")
11     public void testUserManager() {
12         
13         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
14         IUserManagerService userBean = (IUserManagerService) ctx.getBean("userManager");
15         userBean.addUser("zhaolibin", "buzhidao");
16     }
17 }
TestUserManager

 

Junit运行实例后,打印如下结果:

--------------UserManager addUser-------------

 

 

一: XML配置AOP:

 

现在我们首先用xml文件配置方式来实现aop,spring aop中有好多切面、通知之类的理论知识在此不多说了,直接来实例,写一个切面类,在类中写上常见几个通知的方法,代码如下:

 1 package com.wangku.spring.util;
 2 
 3 import org.aspectj.lang.ProceedingJoinPoint;
 4 
 5 public class InterceptorAop {
 6 
 7     public void doBefore() {
 8         System.out.println("========执行前置通知==========");
 9     }
10     
11     public void doAferReturning() {
12         System.out.println("=========执行后置通知================");
13     }
14     
15     public void doAfter() {
16         System.out.println("========执行最终通知==========");
17     }
18     
19     public void doAferThrowing() {
20         System.out.println("=============执行意外通知================");
21     }
22     
23     public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
24         
25         System.out.println("=========进入判断方法===========");
26         Object result = pjp.proceed();
27         System.out.println("==========进入退出方法==========");
28         return result;
29     }
30 }
InterceptorAop

 

然后我们需要在spring的xml文件里配置切点类以及对应的方法,代码如下:

		<bean id="aspetBean" class="com.wangku.spring.util.InterceptorAop"/> 
		
		<aop:config>
			<aop:aspect id="aspet" ref="aspetBean">
				 <aop:pointcut expression="execution (* com.wangku.spring.service.impl..*.*(..))" id="cut"/>   	
				 
				 <aop:before pointcut-ref="cut" method="doBefore"/>
				 <aop:after-returning pointcut-ref="cut" method="doAferReturning"/>
				 <aop:after pointcut-ref="cut" method="doAfter"/>
				 <aop:after-throwing pointcut-ref="cut" method="doAferThrowing"/>
				 <aop:around pointcut-ref="cut" method="doAround"/>
			</aop:aspect>
		</aop:config> 

在此大概说下上面的切入点表达式:

1 execution (* com.wangku.spring.service.impl..*.*(..))
2 execution : 表示执行
3 第一个*号 : 表示返回值类型, *可以是任意类型
4 com.wangku.spring.service.impl : 代表扫描的包
5 .. : 代表其底下的子包也进行拦截  
6 第二个*号 : 代表对哪个类进行拦截,*代表所有类  
7 第三个*号 : 代表方法  *代表任意方法
8 (..) : 代表方法的参数有无都可以

 




 此时配置已经起作用了,再次运行测试用例可以发下打印如下结果:

========执行前置通知==========
=========进入判断方法===========
--------------UserManager addUser-------------
==========进入退出方法==========
========执行最终通知==========
=========执行后置通知================

 

细心的同学可以观察下不同的通知执行的时机。

上面就是xml配置的情况,但通常情况下 xml配置略显繁琐,所以我们来看看注解配置如何进行。

二:注解配置AOP

 

使用注解使一切都变得简单,首先spring配置文件中加入注解和支持注释的配置,代码如下:

        <aop:aspectj-autoproxy/> 
        <context:annotation-config />
        <context:component-scan base-package="com.wangku.spring" />

 

最下面的一行配置是指我们要扫描的包。此时有人可能注意到了我们之前写的serviceImpl中的一句注解:@Service("manager")

此时我们的xml是支持扫描的,所以我们在spring配置文件中去掉bean的配置,值保持上面的这几行配置文件,然后在Junit里执行下面代码:

    @Test
    @SuppressWarnings("resource")
    public void testUserManager() {
        
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        IUserManagerService userBean = (IUserManagerService) ctx.getBean("manager");
        userBean.addUser("zhaolibin", "buzhidao");
    }    

 

打印出了我们意料中的结果,然后我们开始用注解的方式配置aop切面类,具体代码如下:

 1 package com.wangku.spring.util;
 2 
 3 import org.aspectj.lang.annotation.After;
 4 import org.aspectj.lang.annotation.Aspect;
 5 import org.aspectj.lang.annotation.Before;
 6 import org.aspectj.lang.annotation.Pointcut;
 7 
 8 @Aspect
 9 public class Interceptor {
10     
11     @Pointcut("execution (* com.wangku.spring.service.impl..*.*(..))")
12     private void anyMethod() {
13         System.out.println("============进入anyMethod方法==============");
14     }
15     
16     @Pointcut("execution (* com.wangku.spring.service.test..*.*(..))")
17     private void someMethod() {
18         System.out.println("============进入someMethod方法==============");
19     }
20     
21     @Before("anyMethod()")
22     public void doBefore() {
23         System.out.println("==========执行前置通知===============");
24     }
25     
26     @After("someMethod()")
27     public void doAfter() {
28         System.out.println("===========执行最终通知==============");
29     }
30 }
Interceptor

 

因为是切面类,所以使用@Aspect注解此类,然后用@Pointcut来指定切面表达式,此处我定义了2个切面表达式。

在spring配置文件中加入切面类的bean,如下

<bean id="interceptor" class="com.wangku.spring.util.Interceptor"/>

 

此时再次运行上面的Junit,会发现打印如下结果:

==========执行前置通知===============
--------------UserManager addUser-------------

 

注解已经执行了。接着在service下面再建立另一个test包,下面新建一个UserTestServiceImpl类进行多切面表达式的测试, 代码如下

 1 package com.wangku.spring.service.test;
 2 
 3 import org.springframework.stereotype.Service;
 4 
 5 import com.wangku.spring.model.UserManager;
 6 import com.wangku.spring.service.IUserManagerService;
 7 
 8 @Service("tester")
 9 public class UserTestServiceImpl implements IUserManagerService{
10 
11     public void addUser(String userName, String password) {
12         System.out.println("--------------UserTestServiceImpl addUser-------------");
13     }
14 
15     public void updateUser(int userId, String userName, String password) {
16         System.out.println("--------------UserTestServiceImpl updateUser-------------");
17     }
18 
19     public void deleteUser(int userId) {
20         System.out.println("--------------UserTestServiceImpl deleteUser-------------");
21     }
22 
23     public UserManager findUser(int userId) {
24         System.out.println("--------------UserTestServiceImpl findUser-------------");
25         return null;
26     }
27 }
UserTestServiceImpl

 

此时利用execution (* com.wangku.spring.service.test..*.*(..))切面表达式来扫描我们新建的测试类,在Junit测试用例中执行以下代码:

        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        IUserManagerService userBean = (IUserManagerService) ctx.getBean("tester");
        userBean.addUser("zhaolibin", "buzhidao");

 

执行结果如下:

--------------UserTestServiceImpl addUser-------------
===========执行最终通知==============

 

由此可见,我们可以配置不同的切面表达式针对不同的类进行切面处理,当然通常情况下多用于权限等的控制。

 

spring aop的xml文件配置还有其他不同的形式,例如通过

        <aop:config>
            <aop:advisor advice-ref=""/>
        </aop:config>

 

这种形式,不过殊途同归,只要了解其中的原理就好。

关于爱程序网 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 人才招聘 - 帮助