您的位置:首页 > 编程语言 > Java开发

AOP实现(二)---Spring框架中的AOP应用

2011-12-24 10:21 253 查看
一:传统方式(Spring1.0)

使用Spring中的AOP API中定义的接口来定义Adivce(通知,做什么事情),并设置代理对象(配置文件中使用org.springframework.aop.framework.ProxyFactoryBean)然后在程序中使用这个代理对象。

还有基于XML配置方式和注解方式。

1.方法前通知,实现接口MethodBeforeAdivce

package proxy;
2
import java.lang.reflect.Method;
4
import org.springframework.aop.MethodBeforeAdvice;
6
public class BeforeLogin implements MethodBeforeAdvice{
8
public void before(Method method, Object[] args, Object target)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("执行前");
}
}


2.被代理对象实现的接口

package proxy;
2
public interface ILogin {
public void login(String username,String password);
}


3.被代理对象

package proxy;
2
public class Login implements ILogin{
public void login(String username, String password) {
// TODO Auto-generated method stub
if("tazi".equals(username)&&"123".equals(password))
System.out.println("login success!");
else
System.out.println("login fail!");
10
}
}


4.配置文件

<bean id='beforeLogin' class="proxy.BeforeLogin">
</bean>
<bean id='login' class="proxy.Login"></bean>
<bean id='my_proxy'
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>proxy.ILogin</value>
</property>
<property name="target" ref='login'></property>
<property name="interceptorNames">
<list>
<value>beforeLogin</value>
</list>
</property>
</bean>


配置文件中<property name="interceptorNames">下的<list>子标签也可以用

<idref local='interceptorLogin2'/>

5.测试

public class Test {
public static void main(String[] args) {
ApplicationContext apc=new ClassPathXmlApplicationContext("applicationContext.xml");
ILogin login=(ILogin)apc.getBean("my_proxy");
login.login("tazi", "123");
}
}


运行结果:

执行前
login success!


另外还有方法后通知,实现AfterReturingAdvice.它仅在方法正常返回后被调用,若方法执行中出现异常则不被调用。它可以看到方法的返回值,却不能改变它,由返回类型是void也可以知道。

void    afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable


环绕型通知,实现org.aopalliance.intercept.MethodInterceptor(aop联盟定义的,便于在实现规范的aop中迁移)

Object invoke(MethodInvocation invocation) throws Throwable


注意返回值是Object类型,如果希望不影响返回值,应当返回原方法的返回值,即

Object result=invocation.proceed();
//...
return result;


invocation参数中封装了原方法的信息,有getMethod(),getArguments()等方法。

异常通知ThrowsAdvice,此接口为标签接口,可以自定义方法名称,只要是如下形式

aferThrowing([Method],[args],[target],Throwable的子类)

二 XML文件的方式

1.引入AOP命名空间

<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd ">
<!-- 注解方式必须加上 <aop:aspectj-autoproxy/> -->
<!-- 目标对象 -->
<bean id="personService" class="com.tazi.service.impl.PersonServiceBean"></bean>
<!-- 横切面 -->
<bean id="myInterceptor" class="com.tazi.service.MyInterceptor"></bean>
<!-- 所有aop配置 -->
<aop:config>
<!-- 定义一个切面 -->
<aop:aspect id="asp" ref="myInterceptor">
<!-- 定义一个切入点,也可以作为<aop:config>的子标签 -->
<aop:pointcut id="mycut" expression="execution (* com.tazi.service.impl.PersonServiceBean.*(..))"/>
<!-- 前置通知,注意方法没有参数或者有一个JoinPoint类型的参数 -->
<aop:before pointcut-ref="mycut" method="doAccess"/>
<aop:after pointcut-ref="mycut" method="afterRet"/>
32
</aop:aspect>
</aop:config>
</beans>


2.建立目标对象,自定义的切面对象(不需要实现任何接口)

package com.tazi.service;
2
3
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/*
* 切面,交给Spring容器管理
*/
9
public class MyInterceptor {
11
/*
* 前置通知
*/
public void doAccess(){
System.out.println("前置通知");
}
18
public void afterRet(JoinPoint jPoint){
System.out.println(jPoint.getSignature().getDeclaringTypeName());
System.out.println(jPoint.getSignature().getName());
System.out.println("后置通知");
}
public void after(){
System.out.println("最终通知");
}
public void expHandle(Exception e) {
System.out.println("抛出异常"+e);
}
30
public Object huan(ProceedingJoinPoint pjp)throws Throwable{
System.out.println("进入方法");
Object result=pjp.proceed();
System.out.println("退出方法");
return result;
36
}
}


3.定义切入点,使用切入点表达式语言

4.配置xml文件

5.测试

三:使用注解的方式

在Spring的配置文件中引入aop命名空间

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

xsi:schemaLocation中加入
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd

1.打开注解方式的配置项

注解本身不能干活,需要处理器

使用<aop:aspectj-autoproxy/> 提供对注解的解释功能。

2.定义切面、切入点(对业务Bean里面的哪些方法进行拦截),定义通知(拦截到方法以后所要做的工作)。

业务接口和业务方法如下:

package com.tazi.service.impl;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tazi.service.PersonService;

public class PersonServiceBean implements PersonService {

public void save(String name) {
// TODO Auto-generated method stub
System.out.println("save");
throw new RuntimeException("例外");
}

public void update() {
// TODO Auto-generated method stub

}
public static void main(String[] args) {
ApplicationContext apc=new ClassPathXmlApplicationContext("bean.xml");
PersonService pService=(PersonService)apc.getBean("personService");
pService.save("tazi");
}

public String getPersonName(Integer id) {
// TODO Auto-generated method stub
System.out.println("getName");
return "tazi";
}

}


定义切面,使用@Aspect注解,前提是把该切面交给Spring来管理,否则注解没有任何作用。

定义切入点,使用切入点表达式,形如如下形式:

execution表示运行时,后面是[返回值]+空格+包名.类名(包名..类名则表示连同子包)+点号+方法+(..)

注意:方法(..)表示方法的参数任意,*可以表示任意

切入点的名称定义是以一个方法的形式。名称连括号也带上。

定义通知
根据所作的工作是方法的前后位置,有不同的通知。

1 package com.tazi.service;
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 /*
12  * 切面,交给Spring容器管理
13  */
14 @Aspect
15 public class MyInterceptor {
16     /*
17      * 定义一个切入点
18 */
19     @Pointcut ("execution (* com.tazi.service.impl.PersonServiceBean.*(..))")
20     private void anyMethod(){}
21
22     /*
23      * 前置通知
24 */
25     @Before("anyMethod() &&args(name)")//多个条件,与参数的名字相同,既然如此,也说明应用的方法必须有一个String类型的参数
26     public void doAccess(String name){
27         System.out.println("前置通知"+name);
28     }
29
30     @AfterReturning(pointcut="anyMethod()",returning="result")//必须是方法正常执行,若抛出异常则不可能被调用,这里加了返回值,也暗示了所拦截的方法必须带有一个String类型的返回值
31     public void afterRet(String result){
32         System.out.println("后置通知"+result);
33     }
34     @After("anyMethod()") //无论方法是否抛出异常,都会执行它,相当于在try catch的finally中执行
35     public void after(){
36         System.out.println("最终通知");
37     }
38     @AfterThrowing(pointcut="anyMethod()",throwing="e")//当抛出异常时
39     public void expHandle(Exception e) {
40         System.out.println("抛出异常"+e);
41     }
42
43     @Around("anyMethod()")        //环绕方法前后,特别适合于权限管理,如果有权限,就调用pjp.proceed()否则不调用,环绕型的通知的方法签名必须是如下形式
44     public Object huan(ProceedingJoinPoint pjp)throws Throwable{
45         System.out.println("进入方法");
46         Object result=pjp.proceed();
47         System.out.println("退出方法");
48         return result;
49
50     }
51 }


3.最后把切面和业务Bean都在xml配置文件中配置,交给Spring容器管理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: