使用Spring的注解方式实现AOP

 

 

Spring提供了两种切面使用方式,实际工作中使用其一就可以:

(1)、基于XML配置方式进行AOP开发

(2)、基于注解方式进行AOP开发

 

 

1、新建项目,引入必要jar文件

2、在配置文件中引入aop命名空间,启动对@AspectJ注解的支持:

<?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:context="http://www.springframework.org/schema/context" 
       xmlns:aop="http://www.springframework.org/schema/aop"      
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
        <aop:aspectj-autoproxy/> 
</beans>

3、创建业务bean,供测试使用:

package com.wxy.service;

public interface PeopleService {
    public void save(String name);

    public void update(String name, Integer id);

    public String getPeopleName(Integer id);
}
----------------------------------------------------------------
package com.wxy.service.impl;

import com.wxy.service.PeopleService;

public class PeopleServiceBean implements PeopleService {

    @Override
    public String getPeopleName(Integer id) {
        System.out.println(" 我是getPeopleName(Integer id)方法");
        return "wxy";
    }

    @Override
    public void save(String name) {
        System.out.println(" 我是save(String name)方法");
    }

    @Override
    public void update(String name, Integer id) {
        System.out.println(" 我是update(String name, Integer id)方法");
    }

}

在beans.xml中配置,将bean交给spring容器管理:

    ………

    <aop:aspectj-autuproxy/>

    <bean id="peopleService" class="com.wxy.service.impl.PeopleServiceBean"/>

</beans>

4、定义切面:

package com.wxy.service;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

/**
*  基于注解方式申明切面
*  用来定义我们要拦截的方法
*/
@Aspect
public class MyInterceptor {

    /**
     * 切入点定义 
     * com.wxy.service.impl.PeopleServiceBean该类的所有方法将被拦截
     */
    @Pointcut("execution(* com.wxy.service.impl.PeopleServiceBean.*(..))")
    private void anyMethod() {
    }

    /**
     * 前置通知
     * 拦截到方法,在方法执行前,先执行前置通知
     * @param userName
     */
    @Before("anyMethod()")
    public void doAccessCheck(String userName) {
        System.out.println("前置通知");
    }
}

  在配置文件beans.xml中配置切面,交给spring来管理:

……….

    <bean id="myIntercepetor" class="com.wxy.service.MyInterceptor"/>

</beans>

5、  开发客户端调用业务端bean,测试切面的拦截机制:

public class SpringAOPTest {

    public static void main(String[] args) {
        ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
        PeopleService peopleService = (PeopleService) cxt.getBean("peopleService");
        peopleService.save("wxy");
    }
}


测试结果:

2011-8-23 22:25:09 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9: display name [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]; startup date [Tue Aug 23 22:25:09 CST 2011]; root of context hierarchy
2011-8-23 22:25:09 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
2011-8-23 22:25:09 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]: org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9
2011-8-23 22:25:09 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9: defining beans [org.springframework.aop.config.internalAutoProxyCreator,myInterceptor,peopleService]; root of factory hierarchy
前置通知:wxy
我是save()方法


使用Spring的注解方式实现AOP的细节  :

 

1、修改切面类,增加其他通知注解:

package com.wxy.service;

/**
 * 切面
 *
 */
@Aspect
public class MyInterceptor {
    @Pointcut("execution (* com.wxy.service.impl.PeopleServiceBean.*(..))")
    private void anyMethod() {
    }//声明一个切入点

    @Before("anyMethod() && args(name)")
    public void doAccessCheck(String name) {
        System.out.println("前置通知:" + name);
    }

    @AfterReturning(pointcut = "anyMethod()", returning = "result")
    public void doAfterReturning(String result) {
        System.out.println("后置通知:" + result);
    }

    @After("anyMethod()")
    public void doAfter() {
        System.out.println("最终通知");
    }

    @AfterThrowing(pointcut = "anyMethod()", throwing = "e")
    public void doAfterThrowing(Exception e) {
        System.out.println("例外通知:" + e);
    }

    @Around("anyMethod()")
    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
        //if(){//判断用户是否在权限
        System.out.println("进入方法");
        Object result = pjp.proceed();
        System.out.println("退出方法");
        //}
        return result;
    }

}


PeopleServiceBean修改,添加例外代码段:

package com.wxy.service.impl;

import com.wxy.service.PeopleService;

public class PeopleServiceBean implements PeopleService {

    public String getPersonName(Integer id) {
        System.out.println("我是getPersonName()方法");
        return "xxx";
    }

    public void save(String name) {
        throw new RuntimeException("这是个美丽的例外");
        //System.out.println("我是save()方法");
    }

    public void update(String name, Integer id) {
        System.out.println("我是update()方法");
    }

}


重新运行测试类,测试结果:

2011-8-23 22:37:30 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9: display name [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]; startup date [Tue Aug 23 22:37:30 CST 2011]; root of context hierarchy
2011-8-23 22:37:30 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
2011-8-23 22:37:30 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9]: org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9
2011-8-23 22:37:30 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@e2dae9: defining beans [org.springframework.aop.config.internalAutoProxyCreator,myInterceptor,peopleService]; root of factory hierarchy
前置通知:wxy
进入方法
最终通知
例外通知:java.lang.RuntimeException: 这是个美丽的例外
Exception in thread "main" java.lang.RuntimeException: 这是个美丽的例外
	at com.wxy.service.impl.PeopleServiceBean.save(PeopleServiceBean.java:13)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:307)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
	at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:50)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.aspectj.AspectJAfterAdvice.invoke(AspectJAfterAdvice.java:42)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:54)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:77)
	at com.wxy.service.MyInterceptor.doBasicProfiling(MyInterceptor.java:46)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:627)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:616)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:64)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:160)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
	at $Proxy10.save(Unknown Source)
	at com.wxy.test.SpringAOPTest.main(SpringAOPTest.java:14)

 

Tips:

spring aop 切点表达式配置pointcut execution

Spring AOP 用户可能会经常使用 execution pointcut designator。执行表达式的格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。你会使用的最频繁的返回类型模式是 * ,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。

下面给出一些常见切入点表达式的例子。

任意公共方法的执行:

execution(public * *(..))

任何一个以“set”开始的方法的执行:

execution(* set*(..))

AccountService 接口的任意方法的执行:

execution(* com.xyz.service.AccountService.*(..))

定义在service包里的任意方法的执行:

execution(* com.xyz.service.*.*(..))

定义在service包或者子包里的任意方法的执行:

execution(* com.xyz.service..*.*(..))

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值