首页 > 编程语言 > 详细

武林秘籍之Spring AOP 切面编程的简单应用

时间:2015-12-16 02:14:19      阅读:298      评论:0      收藏:0      [点我收藏+]

bubuko.com,布布扣
年轻人,我观你骨骼精奇,定是万里无一的练武奇才,老夫这里有一本失传已久的武林秘籍,现赠于你,望你勤加苦练,早日修成正果...

AOP(面向切面编程):Aspect Oriented Programming

第一式、使用切面编程需要的配置

<aop:aspectj-autoproxyexpose-proxy="true"/>

  开启切面编程功能,需要在applicationContext.xml文件中配置。
  作用是:声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,植入切面

第二式、切面编程

  • @Aspect
    放在类头上,把这个类作为一个切面即声明一个切面
  • @Pointcut
    放在方法头上,定义一个可被别的方法引用的切入点表达式。
    Pointcut是Join Point(连接点)的集合,即它是程序中需要注入Advice(切入点上执行的行为)的位置的集合,指明Advice要在什么样的条件下才能被触发。

    • 2.1、Pointcut表达式定义:Pointcut 是指哪些方法需要被执行"AOP",是由"Pointcut Expression"来描述的。 Pointcut可以有下列方式来定义或者通过&& || 和!的方式进行组合。
      args()
      execution()
      this()
      target()
      within()
      annotation
    • 2.2、Pointcut表达式的格式:其中execution 是用的最多的,其格式为:execution(方法操作权限?返回值?方法所在包?方法名(参数)异常?),其中返回值,方法名和参数是必须的。
    • 常用Pointcut表达式的讲解:execution(?com.glodon.gcxx.dao.hibimpl..(..)) ,这是com.glodon.gcxx.dao.hibimpl 包下所有的类的所有方法。
      第一个
      代表所有的返回值类型 ,第二个代表所有的类, 第三个代表类所有方法 ,最后一个..代表所有的参数。
      下面给出一些常见切入点表达式的例子。

    • 1.任意公共方法的执行:execution(public * *(..))
      2.任何一个以“set”开始的方法的执行:execution(* set*(..))
      3.AccountService 接口的任意方法的执行:execution(* com.xyz.service.AccountService.*(..))
      4.定义在service包里的任意方法的执行:execution(* com.xyz.service.*.*(..))
      5.定义在service包或者子包里的任意类的任意方法的执行:execution(* com.xyz.service..*.*(..))
      ?
    • Pointcut 可以通过Java注解和XML两种方式配置,如下所示
    • <aop:config>
      <aop:aspectrefaop:aspectref="aspectDef">
      <aop:pointcutidaop:pointcutid="pointcut1"expression="execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))"/>
      <aop:before pointcut-ref="pointcut1" method="beforeAdvice" />
      </aop:aspect>
      </aop:config>
      ?
      @Component 
      @Aspect 
      public class AspectDef { 
          //@Pointcut("execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))") 
          //@Pointcut("within(com.test.spring.aop.pointcutexp..*)") 
          //@Pointcut("this(com.test.spring.aop.pointcutexp.Intf)") 
          //@Pointcut("target(com.test.spring.aop.pointcutexp.Intf)") 
          //@Pointcut("@within(org.springframework.transaction.annotation.Transactional)") 
          //@Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)") 
          @Pointcut("args(String)") 
          public void pointcut1() { 
          } 
          @Before(value = "pointcut1()") 
          public void beforeAdvice() { 
              System.out.println("pointcut1 @Before..."); 
          }
      ?
  • 3、advice
    5种通知:advice。
    3.1、@Before,前置通知,放在方法头上。
    3.2、@After,后置【finally】通知,放在方法头上。
    3.3、@AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。
    3.4、@AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。
    3.5、@Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。

第三式:主要应用场景

  1. 权限控制
  2. 日志
  3. 事务等等

第四式:例子

首先在applicationContext.xml配置中配置:<aop:aspectj-autoproxy expose-proxy="true" />
1、使用execution定义pointcut方式

  • 定义切面 ?
    /**
     * 通过aop拦截后执行具体操作
     * @author huangqw
     *  */
    @Aspect
    @Component
    public class LogIntercept {
    
    //  com.glodon.action包下任意公共的(public)方法————解析切入点:public表示操作方法的权限,第一个*表示返回值,com.glodon.action表示报名,..表示子包,第二个*表示类,第三个*表示方法名称,(..)表示参数
        @Pointcut(value="execution(public * com.glodon.action..*.*(..))")
        public void writeLog() {
        }
        <br>//    前置拦截,在执行目标方法之前的操作
        @Before("writeLog()")
        public void before() {
            this.printLog("@Before 方法执行前——————做日志");
        }
    //   环绕拦截,在执行目标方法的前后的操作
        @Around("writeLog()")
        public void around(ProceedingJoinPoint pjp) throws Throwable {
            this.printLog("@Around 方法执行前——————做日志");
            pjp.proceed();
            this.printLog("@Around 方法执行后——————做日志");
        }
    //      后置拦截,在执行目标方法之前的操作
        @After("writeLog()")
        public void after() {
            this.printLog("@After 方法执行后——————做日志");
        }
    
        private void printLog(String str) {
            System.out.println(str);
        }
    }
    ?
  • 使用切面?
    /**
     * aop测试类
     * @author huangqw
     */
    @Controller
    public class TestAction {
    
        public void query() {
            System.out.println("查询操作");
        }
    
        public static void main(String[] args) {
    
            @SuppressWarnings("resource")
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("resources/applicationContext.xml");
            TestAction testAction = (TestAction) ctx.getBean("testAction");
            testAction.query();
            ctx.destroy();
        }
    }
    ?
  • 执行结果
    bubuko.com,布布扣
    2、使用注解定义pointcut方式
  • 定义注解:?
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface AroundTest {
        String name() default "测试哈";
    }
    ?
  • 定义切面?
    @Component
    @Aspect
    public class AroundTestInteceptor {
        public AroundTestInteceptor(){
        }
    
      /**
       * 定义切入点
       */
      @Pointcut(value="@annotation(com.glodon.around.AroundTest)")
        public void logAnnotatedMethod() {
        }
    
        /**
         * 拦截方法
         * @param pjp
         * @return
         * @throws Throwable
         */
        @Around("logAnnotatedMethod()")
        public Object inteceptorAction(ProceedingJoinPoint pjp) throws Throwable {
            Object o = null;
            MethodSignature joinPointObject = (MethodSignature) pjp.getSignature(); 
            Method method = joinPointObject.getMethod();
            boolean flag = method.isAnnotationPresent(AroundTest.class) ;    
            if (flag) {
                   AroundTest annotation = method.getAnnotation(AroundTest.class); 
                    Date enterDate = new Date();
                    System.out.println("开始执行方法:" + annotation.name());
                      //用于执行委托对象的目标方法
                      o = pjp.proceed();
                      Date leaveDate = new Date();
                      System.out.println("结束执行方法:"+ annotation.name() +",方法执行的时间:" + (leaveDate.getTime() - enterDate.getTime()));
            }
            return o;
        }
    }
    ?
  • 使用切面?
    /**
     * aop测试类
     * @author huangqw
     */
    @Controller
    public class TestAction {
    
        @AroundTest(name="ceshi")
        public void query() {
            System.out.println("查询操作");
        }
    
        public static void main(String[] args) {
            @SuppressWarnings("resource")
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("resources/applicationContext.xml");
            TestAction testAction = (TestAction) ctx.getBean("testAction");
            testAction.query();
            ctx.destroy();
        }
    }
    ?
  • 执行结果
    bubuko.com,布布扣
    .
    .
    .
    .
    .
    .
    年轻人,老夫已将所有功力传授与你,望你勤加苦练...阿弥陀佛
    bubuko.com,布布扣

武林秘籍之Spring AOP 切面编程的简单应用

原文:http://843977358.iteye.com/blog/2264143

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!