zoukankan      html  css  js  c++  java
  • 【Spring AOP】Spring AOP的使用方式【Q】

    Spring AOP的三种使用方式

    • 经典AOP使用方式
    • 改进XML配置方式
    • 基于注解的方式

    第1种方式可以作为理解spring配置AOP的基础,是最原始的配置方式,也体现了spring处理的过程。
    使用ProxyFactoryBean配置有些欠优雅,在spring2.0里新的xml配置元素体现了改进。Spring2.0在aop命名空间里提供了一些配置元素,简化了把类转化为切面的操作,即第2 种XML方式,本质的使用同第1种方式,只是简化配置,隐藏细节。
    第3种方式是基于注解的,也是比较推荐的使用方式。

    经典AOP使用方式

    Spring中提供:前置通知     环绕通知     后置通知     异常通知  引入通知
    分别需要实现如下接口:

    MethodBeforeAdvice   MethodInteceptor  AfterReturningAdvice   ThrowsAdvice

    其中引入通知是通过配置的,实现自定义切入点,和上述四个通知配合使用

    被代理的对象(被代理对象需要实现接口)

    以MethodBeforeAdvice(环绕通知)为例

    XML配置如下,

    代理对象:ProxyFactoryBean 这是Spring框架提供出来的,我们直接使用,并配置相关属性。

    改进XML配置方式

    为了简化配置,下面是使用普通类,通过aop标签指定来配置AOP。无需再实现上述经典AOP的几个接口。
    以一个案例的形式对xml的开发形式进行简要分析,定义一个切面类。

    public class MyAspectXML {
    
        public void before(){
            System.out.println("MyAspectXML====前置通知");
        }
    
        public void afterReturn(Object returnVal){
            System.out.println("后置通知-->返回值:"+returnVal);
        }
    
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("MyAspectXML=====环绕通知前");
            Object object= joinPoint.proceed();
            System.out.println("MyAspectXML=====环绕通知后");
            return object;
        }
    
        public void afterThrowing(Throwable throwable){
            System.out.println("MyAspectXML======异常通知:"+ throwable.getMessage());
        }
    
        public void after(){
            System.out.println("MyAspectXML=====最终通知..来了");
        }
    }
    

    通过配置文件的方式声明如下(spring-aspectj-xml.xml):

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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.xsd">
    
        <!--<context:component-scan base-package=""-->
    
        <!-- 定义目标对象 -->
        <bean name="productDao" class="com.zejian.spring.springAop.dao.daoimp.ProductDaoImpl" />
    
        <!-- 定义切面 -->
        <bean name="myAspectXML" class="com.zejian.spring.springAop.AspectJ.MyAspectXML" />
        <!-- 配置AOP 切面 -->
        <aop:config>
            <!-- 定义切点函数 -->
            <aop:pointcut id="pointcut" expression="execution(* com.zejian.spring.springAop.dao.ProductDao.add(..))" />
    
            <!-- 定义其他切点函数 -->
            <aop:pointcut id="delPointcut" expression="execution(* com.zejian.spring.springAop.dao.ProductDao.delete(..))" />
    
            <!-- 定义通知 order 定义优先级,值越小优先级越大-->
            <aop:aspect ref="myAspectXML" order="0">
                <!-- 定义通知
                method 指定通知方法名,必须与MyAspectXML中的相同
                pointcut 指定切点函数
                -->
                <aop:before method="before" pointcut-ref="pointcut" />
    
                <!-- 后置通知  returning="returnVal" 定义返回值 必须与类中声明的名称一样-->
                <aop:after-returning method="afterReturn" pointcut-ref="pointcut"  returning="returnVal" />
    
                <!-- 环绕通知 -->
                <aop:around method="around" pointcut-ref="pointcut"  />
    
                <!--异常通知 throwing="throwable" 指定异常通知错误信息变量,必须与类中声明的名称一样-->
                <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="throwable"/>
    
                <!--
                     method : 通知的方法(最终通知)
                     pointcut-ref : 通知应用到的切点方法
                    -->
                <aop:after method="after" pointcut-ref="pointcut"/>
            </aop:aspect>
        </aop:config>
    </beans>
    

    声明方式和定义方式在代码中已很清晰了,了解一下即可,在实际开发中,会更倾向与使用注解的方式开发,毕竟更简单更简洁。

    基于注解AOP使用方式

    Spring在新版本中对AOP功能进行了增强,体现在这么几个方面:
    •在XML配置文件中为AOP提供了aop命名空间
    •增加了AspectJ切点表达式语言的支持
    •可以无缝地集成AspectJ

    那我们使用@AspectJ来玩AOP的话,学什么??其实也就是上面的内容,学如何设置切点、创建切面、增强的内容是什么...

    定义切入点函数
    在案例中,定义过滤切入点函数时,是直接把execution已定义匹配表达式作为值传递给通知类型的如下:

    @After(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")
      public void after(){
          System.out.println("最终通知....");
      }
    

    除了上述方式外,还可采用与ApectJ中使用pointcut关键字类似的方式定义切入点表达式如下,使用@Pointcut注解:

    /**
     * 使用Pointcut定义切点
     */
    @Pointcut("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")
    private void myPointcut(){}
    
    /**
     * 应用切入点函数
     */
    @After(value="myPointcut()")
    public void afterDemo(){
        System.out.println("最终通知....");
    }
    

    使用@Pointcut注解进行定义,应用到通知函数afterDemo()时直接传递切点表达式的函数名称myPointcut()即可,比较简单,下面接着介绍切点指示符。

    基于注解的AOP实例

    定义目标类接口和实现类

    /**
     * Created by zejian on 2017/2/19.
     * Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
     */
     //接口类
    public interface UserDao {
    
        int addUser();
    
        void updateUser();
    
        void deleteUser();
    
        void findUser();
    }
    
    //实现类
    import com.zejian.spring.springAop.dao.UserDao;
    import org.springframework.stereotype.Repository;
    
    /**
     * Created by zejian on 2017/2/19.
     * Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
     */
    @Repository
    public class UserDaoImp implements UserDao {
        @Override
        public int addUser() {
            System.out.println("add user ......");
            return 6666;
        }
    
        @Override
        public void updateUser() {
            System.out.println("update user ......");
        }
    
        @Override
        public void deleteUser() {
            System.out.println("delete user ......");
        }
    
        @Override
        public void findUser() {
            System.out.println("find user ......");
        }
    }
    

    使用Spring 2.0引入的注解方式,编写Spring AOP的aspect 类:

    @Aspect
    public class MyAspect {
    
        /**
         * 前置通知
         */
        @Before("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")
        public void before(){
            System.out.println("前置通知....");
        }
    
        /**
         * 后置通知
         * returnVal,切点方法执行后的返回值
         */
        @AfterReturning(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))",returning = "returnVal")
        public void AfterReturning(Object returnVal){
            System.out.println("后置通知...."+returnVal);
        }
    
    
        /**
         * 环绕通知
         * @param joinPoint 可用于执行切点的类
         * @return
         * @throws Throwable
         */
        @Around("execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("环绕通知前....");
            Object obj= (Object) joinPoint.proceed();
            System.out.println("环绕通知后....");
            return obj;
        }
    
        /**
         * 抛出通知
         * @param e
         */
        @AfterThrowing(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))",throwing = "e")
        public void afterThrowable(Throwable e){
            System.out.println("出现异常:msg="+e.getMessage());
        }
    
        /**
         * 无论什么情况下都会执行的方法
         */
        @After(value="execution(* com.zejian.spring.springAop.dao.UserDao.addUser(..))")
        public void after(){
            System.out.println("最终通知....");
        }
    }
    

    编写配置文件交由Spring IOC容器管理

    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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.xsd">
    
        <!-- 启动@aspectj的自动代理支持-->
        <aop:aspectj-autoproxy />
    
        <!-- 定义目标对象 -->
        <bean id="userDaos" class="com.zejian.spring.springAop.dao.daoimp.UserDaoImp" />
        <!-- 定义aspect类 -->
        <bean name="myAspectJ" class="com.zejian.spring.springAop.AspectJ.MyAspect"/>
    </beans>
    

    编写测试类

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations= "classpath:spring/spring-aspectj.xml")
    public class UserDaoAspectJ {
        @Autowired
        UserDao userDao;
    
        @Test
        public void aspectJTest(){
            userDao.addUser();
        }
    }
    

    简单说明一下,定义了一个目标类UserDaoImpl,利用Spring2.0引入的aspect注解开发功能定义aspect类即MyAspect,在该aspect类中,编写了5种注解类型的通知函数,分别是前置通知@Before、后置通知@AfterReturning、环绕通知@Around、异常通知@AfterThrowing、最终通知@After,这5种通知与前面分析AspectJ的通知类型几乎是一样的,并注解通知上使用execution关键字定义的切点表达式,即指明该通知要应用的目标函数,当只有一个execution参数时,value属性可以省略,当含两个以上的参数,value必须注明,如存在返回值时。当然除了把切点表达式直接传递给通知注解类型外,还可以使用@pointcut来定义切点匹配表达式,这个与AspectJ使用关键字pointcut是一样的,后面分析。目标类和aspect类定义完成后,最后需要在xml配置文件中进行配置,同样的所有类的创建都交由SpringIOC容器处理,注意,使用Spring AOP 的aspectJ功能时,需要使用以下代码启动aspect的注解功能支持:

    <aop:aspectj-autoproxy />
    

    另外,开启AOP也可以通过代码配置。使用 Java Configuration 方式使能@AspectJ

    @Configuration
    @EnableAspectJAutoProxy
    public class AppConfig {
    }
    

    参考资料:
    Spring AOP三种配置详细介绍
    关于 Spring AOP (AspectJ) 你该知晓的一切
    Spring AOP就是这么简单啦
    彻底征服 Spring AOP 之 理论篇
    JAVA动态代理 和 Spring AOP 4种通知的简单实现

  • 相关阅读:
    grunt in webstorm
    10+ Best Responsive HTML5 AngularJS Templates
    响应式布局
    responsive grid
    responsive layout
    js event bubble and capturing
    Understanding Service Types
    To add private variable to this Javascript literal object
    Centering HTML elements larger than their parents
    java5 新特性
  • 原文地址:https://www.cnblogs.com/z00377750/p/11793088.html
Copyright © 2011-2022 走看看