本文说到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>
下面图文说明我们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 }
然后, 建立一个测试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 }
接着写一个实现类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 }
此时在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>
配置好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 }
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 }
然后我们需要在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 }
因为是切面类,所以使用@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 }
此时利用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>
这种形式,不过殊途同归,只要了解其中的原理就好。