zoukankan      html  css  js  c++  java
  • spring之AOP

    一、AOP的概念

        AOP(Aspect Oriented Programming),即面向切面编程,是面向对象编程的的有力补充。面向对象编程关注的主要是业务处理,与之关系不大的部分是切面关注点。他们经常发生在核心业务的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心业务和切面关注点分离开来。主要是利用动态代理来实现AOP的。

    aop中几个重要的概念

    1、切面(aspect)

    类是对物体特征的抽象,切面就是对横切关注点的抽象,用于编写多个advice;

    2、连接点(joinpoint)

    程序执行过程中明确的点,如方法的调用,在Spring中连接点指的就是被拦截到的方法;

    3、切入点(pointcut)

    对连接点的定义

    4、增强处理(Advice)

    aop在特定切入点执行的增强处理,有:before、after、around等

    5、织入(weave)

    将切面应用到目标对象并创建代理对象的过程

    二、基于注解方式的实现

    1、jar包的引入

    • spring-aop-3.2.5.RELEASE.jar
    • aopalliance.jar
    • aspectjweaver.jar
    • aspectjrt.jar

    2、bean,xml中引入aop命名空间

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

    3、aop注解扫描配置

    <aop:aspectj-autoproxy/>

    4、注解介绍

    1、@Aspect:定义当前类为切面类

    2、@Before 前置通知:在目标方法之前执行

    3、@After 后置通知:在目标方法之后执行(出不出现异常始终执行)

    4、@AfterReturning 在目标方法完成之后运行(出现异常不执行)

    5、@AfterThrowing 出现异常时执行

    6、@Around 既可以在目标完成之前织入,也可以在目标完成之后织入

    7、@PointCut  定义一个切入点

    注:1、切入点表达式使用规则

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
    
    //有“?”号的部分表示可省略的
    //modifers-pattern表示修饰符如public、protected等,
    //ret-type-pattern表示方法返回类型,
    //declaring-type-pattern代表特定的类,
    //name-pattern代表方法名称,
    //param-pattern表示参数,
    //throws-pattern表示抛出的异常。
    //在切入点表达式中,可以使用*来代表任意字符,用..来表示任意个参数。

    如:

    @Before("execution(* com.pjf.spring.dao.*.*(..))")

    2、pointcut运用

    @Pointcut("execution(* com.pjf.spring.dao.*.*(..))")
    //这里需要定义一个空函数,也就是切入点名myPointcut
        public void myPointcut(){};
        
        @Before("myPointcut()")
        public void before() {
    
            System.out.println("program beginning");
        }

    5、代码实现

    包括hotelDao接口和实现,Hotel实体类,service类、aop类和测试类

    1、HotelDao接口和实现

    import com.pjf.spring.po.Hotel;
    
    public interface HotelDAO {
        public void operate(Hotel hotel);
    }
    import org.springframework.stereotype.Component;
    import com.pjf.spring.po.Hotel;
    @Component(
    "hotelAdd") public class HotelDAOAddImpl implements HotelDAO { public void operate(Hotel hotel) { System.out.println(hotel + "saved!"); }; }

    2、Hotel实体类

    public class Hotel {
        private int id;
        private String hotelName;public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getHotelName() {
            return hotelName;
        }
        public void setHotelName(String hotelName) {
            this.hotelName = hotelName;
        }
        @Override
        public String toString(){
            return hotelName;
        }   
    }

    3、service类

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Component;
    import com.pjf.spring.dao.HotelDAO;
    import com.pjf.spring.po.Hotel;
    
    @Component
    public class HotelService {       
        private HotelDAO hotelDAO;   
        public HotelDAO getHotelDAO() {
            return hotelDAO;
        }    
        @Autowired
        public void setHotelDAO(@Qualifier("hotelAdd") HotelDAO hotelDAO) {
            this.hotelDAO = hotelDAO;
        }
        public void operateHotel(Hotel hotel) {
            hotelDAO.operate(hotel);
        }
    
    }

    4、aop类(打印日志)

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class log {
        // 切入点定义
        @Pointcut("execution(* com.pjf.spring.dao.*.*(..))")
        public void myPointcut() {
        };
    
        // 前置通知 : 在执行目标方法之前执行
        @Before("myPointcut()")
        public void before() {
            System.out.println("开始");
        }
    // @After 后置通知:在目标方法之后执行(出不出现异常始终执行)
        @After("myPointcut()")
        public void after() {
            System.out.println("结束");
        }
    
        //@AfterReturning 在目标方法完成之后运行(出现异常不执行)
        @AfterReturning("myPointcut()")
        public void afterReturning() {
            System.out.println("afterReturning()");
        }
    
        //@AfterThrowing 出现异常时执行
        @AfterThrowing("myPointcut()")
        public void afterThrowing() {
            System.out.println("afterThrowing()");
        }
    
        // @Around 既可以在目标完成之前织入,也可以在目标完成之后织入
        @Around("myPointcut()")
        public void around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("环绕前....");
            pjp.proceed(); // 执行目标方法
            System.out.println("环绕后....");
        }
    }

    5、测试类

    import static org.junit.Assert.*;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import com.pjf.spring.po.Hotel;
    public class HotelServiceSpringTest { @Test public void test() { Hotel hotel =new Hotel(); hotel.setId(1001); hotel.setHotelName("南京金陵饭店"); ApplicationContext ctx= new ClassPathXmlApplicationContext("springBeans.xml"); HotelService hotelService = ctx.getBean("hotelService",HotelService.class);
    hotelService.operateHotel(hotel); } }

    6、结果

    环绕前....
    开始
    南京金陵饭店saved!
    环绕后....
    结束
    afterReturning()

    可以看到最先执行的是around,然后是before,再是around、after、afterReturnning的顺序,但是结果并没有afterThrowing(),这是因为我没在程序HotelDAOAddImpl类的operate方法中抛异常 。

    注:如果程序中我没有编写hotelDao接口,直接编写实现类hotelDaoAddimpl,这时候会怎么样(这时候就需要jar包帮我们实现接口,需要导入cglibjar包)有兴趣可以实验下。

    三、基于xml方式的实现

    1、jar包的引入

         同注解方式一样

    2、bean,xml中引入aop命名空间

         同注解方式一样

    3、代码实现

    包括hotelDao接口和实现,Hotel实体类,service类、aop类和测试类

    1、HotelDao接口和实现、Hotel实体类,service类、和测试类

        同注解方式一样

    2、aop类

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class log {public void before() {
            System.out.println("开始");
        }public void after() {
            System.out.println("结束");
        }public void afterReturning() {
            System.out.println("afterReturning()");
        }public void afterThrowing() {
            System.out.println("afterThrowing()");
        }public void around(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println("环绕前....");
            pjp.proceed(); // 执行目标方法
            System.out.println("环绕后....");
        }
    }

    3、springBeans文件配置

    不需要死记,需要用的时候copy下,然后修改就可以了

    <?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-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    
        <!-- spring注解扫描 -->
        <context:component-scan base-package="com.tuniu.spring.*" />
        <!-- 切面类 -->
        <bean id="log" class="com.tuniu.spring.aop.log"></bean>
    
        <aop:config>
            <!-- 切入点表达式 -->
            <aop:pointcut expression="execution(* com.tuniu.spring.dao.*.*(..))"
                id="daoImplLog" />
            <!-- 增强处理 -->
            <aop:aspect id="ImplLog" ref="log">
                <aop:before method="before" pointcut-ref="daoImplLog" />
                <aop:after method="after" pointcut-ref="daoImplLog" />
                <aop:after-returning method="afterReturning"
                    pointcut-ref="daoImplLog" />
                <aop:after-throwing method="afterThrowing"
                    pointcut-ref="daoImplLog" />
                <aop:around method="around" pointcut-ref="daoImplLog" />
            </aop:aspect>
        </aop:config>
    
    </beans>

    4、结果

    开始
    环绕前....
    南京金陵饭店saved!
    环绕后....
    afterReturning()
    结束

    一般情况下都是用注解方式,但是在某些特殊情况下,如在没有源码的情况下,使用xml配置,当然大部分情况下我们都是有源码的,所以基本上推荐使用注解方式。

     四:aop和annotation的结合

     代码和上面注解的一样

    1、新增annotation类

    package com.pjf.spring.aop;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface OrdLink {
        
        String value();
    }

    2、新增aop类

    package com.pjf.spring.aop;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    
    @Aspect
    @Component
    public class LogManager {
    
        /*切点为@annotation OrdLink注解*/
        @Before("@annotation(ordLink)")
        public void ordLinkLog(OrdLink ordLink) {
            System.out.println(ordLink.value());
        }
    }

    3、修改HotelDAOAddImpl 类

    package com.pjf.spring.dao;
    
    import org.springframework.stereotype.Component;
    import com.pjf.spring.aop.OrdLink;
    import com.pjf.spring.po.Hotel;
    
    @Component("hotelAdd")
    public class HotelDAOAddImpl implements HotelDAO {
        
        @OrdLink("添加酒店")    
        public void operate(Hotel hotel) {
            System.out.println(hotel + "saved!");
        };
    }

    测试结果:

    环绕前....
    开始
    添加酒店
    南京金陵饭店坐落在鼓楼区汉中路2号saved!
    环绕后....
    结束
    afterReturning()
     
  • 相关阅读:
    Kubernetes学习之路(21)之网络模型和网络策略
    Kubernetes学习之路(16)之存储卷
    Kubernetes学习之路(18)之statefulset控制器
    Kubernetes学习之路(28)之镜像仓库Harbor部署
    Kubernetes学习之路(六)之创建K8S应用
    Kubernetes学习之路(十五)之Ingress和Ingress Controller
    nali一款linux下显示IP来源的小工具
    Redis 及RedisBloom 安装
    对java注解与反射的理解
    Java 8 stream的详细用法
  • 原文地址:https://www.cnblogs.com/pjfmeng/p/7645480.html
Copyright © 2011-2022 走看看