zoukankan      html  css  js  c++  java
  • 吴裕雄天生自然SPRINGSpring AOP

    Spring AOP是Spring框架体系结构中非常重要的功能模块之一,该模块提供了面向切面编程实现。面向切面编程在事务处理、日志记录、安全控制等操作中被广泛使用。
        1.AOP的概念
        AOP(Aspect-Oriented Programming),即面向切面编程。它与OOP(Object-Oriented Programming,面向对象编程) 相辅相成,提供了与 OOP 不同的抽象软件结构的视角。在 OOP 中,以类作为程序的基本单元,而AOP中的基本单元是Aspect(切面)。
    
        AOP采取横向抽取机制,即将分散在各个方法中的重复代码提取出来,然后在程序编译或运行阶段,再将这些抽取出来的代码应用到需要执行的地方。这种横向抽取机制,采用传统的OOP是无法办到的,因为OOP实现的是父子关系的纵向重用。但是AOP不是OOP的替代品,而是OOP的补充,它们相辅相成。

    AOP的术语
    
    在Spring AOP框架中,涉及以下常用术语。
    (1)切面
    切面(Aspect)是指封装横切到系统功能(如事务处理)的类。
    (2)连接点
    连接点(Joinpoint)是指程序运行中的一些时间点,如方法的调用或异常的抛出。
    (3)切入点
    切入点(Pointcut)是指那些需要处理的连接点。在Spring AOP 中,所有的方法执行都是连接点,而切入点是一个描述信息,它修饰的是连接点,通过切入点确定哪些连接点需要被处理。切面、连接点和切入点的关系如图所示。

    (4)通知(增强处理)
    由切面添加到特定的连接点(满足切入点规则)的一段代码,即在定义好的切入点处所要执行的程序代码。可以将其理解为切面开启后,切面的方法。因此,通知是切面的具体实现。
    (5)引入
    引入(Introduction)允许在现有的实现类中添加自定义的方法和属性。
    (6)目标对象
    目标对象(Target Object)是指所有被通知的对象。如果AOP 框架使用运行时代理的方式(动态的AOP)来实现切面,那么通知对象总是一个代理对象。
    (7)代理
    代理(Proxy)是通知应用到目标对象之后,被动态创建的对象。
    (8)组入
    组入(Weaving)是将切面代码插入到目标对象上,从而生成代理对象的过程。根据不同的实现技术,AOP织入有三种方式:编译器织入,需要有特殊的Java编译器;类装载期织入,需要有特殊的类装载器;动态代理织入,在运行期为目标类添加通知生成子类的方式。Spring AOP框架默认采用动态代理织入,而AspectJ(基于Java语言的AOP框架)采用编译器织入和类装载器织入。
    基于注解开发AspectJ
    
    先了解一下Spring的通知类型。根据Spring中通知在目标类方法的连接点位置,可以分为6种如下类型:
    
    1.环绕通知
    环绕通知是在目标方法执行前和执行后实施增强,可以应用于日志记录、事务处理等功能。
    2.前置通知
    前置通知是在目标方法执行前实施增强,可应用于权限管理等功能。
    3.后置返回通知
    后置返回通知是在目标方法成功执行后实施增强,可应用于关闭流、删除临时文件等功能。
    
    4.后置(最终)通知
    后置通知是在目标方法执行后实施增强,与后置返回通知不同的是,不管是否发生异常都要执行该通知,可应用于释放资源。
    5.异常通知
    异常通知是在方法抛出异常后实施增强,可以应用于处理异常、记录日志等功能。
    6.引入通知
    引入通知是在目标类中添加一些新的方法和属性,可以应用于修改目标类(增强类)。

    基于注解开发AspectJ的过程
    1.使用Eclipse创建Web应用并导入JAR包
    
    2.创建接口及实现类
    
    3.创建切面类
    
    4.创建配置类
    
    5.创建测试类
    
    6.运行测试类
    package aspectj.dao;
    
    public interface TestDao {
        public void save();
        public void modify();
        public void delete();
    
    }
    package aspectj.dao;
    
    import org.springframework.stereotype.Repository;
    
    @Repository("testDao")
    public class TestDaoImpl implements TestDao {
        @Override
        public void save() {
            System.out.println("保存");
        }
    
        @Override
        public void modify() {
            System.out.println("修改");
        }
    
        @Override
        public void delete() {
            System.out.println("删除");
        }
    }
    package aspectj.annotation;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    
    /**
     * 切面类,在此类中编写各种类型通知
     */
    @Aspect // @Aspect声明一个切面
    @Component // @Component让此切面成为Spring容器管理的Bean
    public class MyAspect {
        /**
         * 定义切入点,通知增强哪些方法。 "execution(* aspectj.dao.*.*(..))" 是定义切入点表达式,
         * 该切入点表达式的意思是匹配aspectj.dao包中任意类的任意方法的执行。
         * 其中execution()是表达式的主体,第一个*表示的是返回类型,使用*代表所有类型;
         * aspectj.dao表示的是需要匹配的包名,后面第二个*表示的是类名,使用*代表匹配包中所有的类; 第三个*表示的是方法名,使用*表示所有方法;
         * 后面(..)表示方法的参数,其中“..”表示任意参数。 另外,注意第一个*与包名之间有一个空格。
         */
    
        @Pointcut("execution(* aspectj.dao.*.*(..))")
        private void myPointCut() {
        }
    
        /**
         * 前置通知,使用Joinpoint接口作为参数获得目标对象信息
         */
        @Before("myPointCut()") // myPointCut()是切入点的定义方法
        public void before(JoinPoint jp) {
            System.out.print("前置通知:模拟权限控制");
            System.out.println(",目标类对象:" + jp.getTarget() + ",被增强处理的方法:" + jp.getSignature().getName());
        }
    
        /**
         * 后置返回通知
         */
        @AfterReturning("myPointCut()")
        public void afterReturning(JoinPoint jp) {
            System.out.print("后置返回通知:" + "模拟删除临时文件");
            System.out.println(",被增强处理的方法:" + jp.getSignature().getName());
        }
    
        /**
         * 环绕通知 ProceedingJoinPoint是JoinPoint子接口,代表可以执行的目标方法 返回值类型必须是Object
         * 必须一个参数是ProceedingJoinPoint类型 必须throws Throwable
         */
        @Around("myPointCut()")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            // 开始
            System.out.println("环绕开始:执行目标方法前,模拟开启事务");
            // 执行当前目标方法
            Object obj = pjp.proceed();
            // 结束
            System.out.println("环绕结束:执行目标方法后,模拟关闭事务");
            return obj;
        }
    
        /**
         * 异常通知
         */
        @AfterThrowing(value = "myPointCut()", throwing = "e")
        public void except(Throwable e) {
            System.out.println("异常通知:" + "程序执行异常" + e.getMessage());
        }
    
        /**
         * 后置(最终)通知
         */
        @After("myPointCut()")
        public void after() {
            System.out.println("最终通知:模拟释放资源");
        }
    
    }
    package aspectj.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.EnableAspectJAutoProxy;
    
    @Configuration // 声明一个配置类
    @ComponentScan("aspectj") // 自动扫描aspectj包下使用的注解
    @EnableAspectJAutoProxy // 开启Spring对AspectJ的支持
    public class AspectjAOPConfig {
    
    }
    package aspectj.config;
    
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    import aspectj.dao.TestDao;
    
    public class AOPTest {
    
        public static void main(String[] args) {
            // 初始化Spring容器ApplicationContext
            AnnotationConfigApplicationContext appCon = new AnnotationConfigApplicationContext(AspectjAOPConfig.class);
            // 从容器中,获取增强后的目标对象
            TestDao testDaoAdvice = appCon.getBean(TestDao.class);
            // 执行方法
            testDaoAdvice.save();
            System.out.println("================");
            testDaoAdvice.modify();
            System.out.println("================");
            testDaoAdvice.delete();
            appCon.close();
        }
    
    }

     

  • 相关阅读:
    jchdl
    jchdl
    UVa 10256 (判断两个凸包相离) The Great Divide
    UVa 11168 (凸包+点到直线距离) Airport
    LA 2572 (求可见圆盘的数量) Kanazawa
    UVa 10652 (简单凸包) Board Wrapping
    UVa 12304 (6个二维几何问题合集) 2D Geometry 110 in 1!
    UVa 10674 (求两圆公切线) Tangents
    UVa 11796 Dog Distance
    LA 3263 (平面图的欧拉定理) That Nice Euler Circuit
  • 原文地址:https://www.cnblogs.com/tszr/p/15310243.html
Copyright © 2011-2022 走看看