Spring基础----AOP(2),Spring 应用

Spring AOP应用

1.aop几个概念:

横切关注点: 对哪些方面进行拦截,拦截后怎么处理。
切面(aspect):切面是横切关注点的抽象。
连接点(joinpoint):被拦截的方法
切入点(pointcut):对连接点进行拦截的定义。
通知(advice):拦截到连接点之后要执行的代码
目标对象:代理的目标对象
织入
引入
2.主要功能:

日志记录
性能统计
安全控制
事物处理
异常处理

3.advice类型:

前置通知(before advice)
返回后通知(after returning advice)
抛出异常后通知(after throwing advice)
后通知(after advice)
环绕通知(around advice)

4.Spring对AOP的支持

Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。

springAOP 的原理:

  • 当启动springy器的时 , 通过扫描或者创建对象
    解析< aop:config >
    1、 解析切入点表达式,把表达式解除出来以后和spring中的bean进行匹配
    2、 如果匹配成功,则为该bean创建代理对象,在创建代理对象的过程中,把目标方法和通知结合在一起了 如果匹配不成功,则直接报错
    3、 当客户端调用getBean时 , 如果该对象有代理对象,则返回代理对象 , 如果该对象没有代理对象,则返回对象本身

简单来说就是把 各种通知 绑定 到 目标方法上

  • 说明:
    spring容器内部会自动判断:
    如果目标类实现了接口,则采用jdkproxy 如果目标类没有实现接口,则采用eglibproxy

目标类

@Component
public class ServiceImp implements Service {
    @Override
    public boolean save() {
        System.out.println("调用dao层方法向数据库存数据");
        return true;
    }
}

切面拦截类

@Component
public class Logger {

    //前置通知,方法执行之前执行
    public void startMethod(JoinPoint joinPoint) {  
        System.out.println(joinPoint.getSignature().getName());  //获取目标方法名称
        System.out.println("前置通知 : 初始化logger~~~~~~~~~");
    }

    //后置通知,方法正常执行完毕之后执行
    public void getReturnMethod(Object user) {  
        System.out.println("后置通知: " + user);
    }

    //最终通知,方法执行之后执行(不管是否发生异常)
    public void finallyMethod() {      
        System.out.println("最终通知 : 结束logger~~~~~~~~~~~");
    }
    
     //异常通知,在方法抛出异常之后执行
    public void throwMethod(Throwable throwable) { 
        System.out.println("异常通知:" + throwable.getMessage());
    }

   ******************************************************************************************
    /*
     * 环绕通知 一般单独使用
     *  如果不执行joinPoint.proceed(); 目标方法是不执行的
     *  在目标方法上下文添加内容  (类似  jdk _ InvocationHandler代理拦截)
     *  可以将以上通知糅合起来
     *  和其他通知区别是: 环绕通知能控制目标方法执行
     *
     *  环绕通知 相当于 通知方法中包含 目标方法 ,如果通知方法返回值会void ,则 客户端调用目标方法时返回的是null
     *  如果有后置通知,环绕通知返回的值就是后置通知获取的值
     *
     * ProceedingJoinPoint (程序连接点 :客户端代理对象调用哪个方法,哪个方法就是连接点)
     * JoinPoint 能够调用该API得到连接点的一些信息
     * */
    public Object aroundMethod(ProceedingJoinPoint joinPoint) {

        try {
            System.out.println("环绕通知:~~~~~~~");
            
            Object object = joinPoint.proceed();  //执行目标方法,返回的是该目标方法的返回值

            System.out.println("目标方法返回值 : " + object);

            return object;  //需要重新将连接点的返回值返回出去
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return "flase";
        }
    }
}

调用目标类的类

@Component
public class Component {
    @Resource
    private Service service;

    public void save(){
        service.save();
    }
}

在这里插入图片描述

Spring 容器 applicationContext.xml

<?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.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
         http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">


    <!--配置切面   注意每个切面的前后顺序,影响程序的先后执行-->
    <aop:config>

        <!--expression 切入点表达式 : 锁定要绑定切面目标类的方法-->
        <aop:pointcut id="former" expression="execution(* AOP.springaop.service.ServiceImp.*(..))"/>

        <!--ref:引向 切面拦截 (将切面绑定到目标类方法)-->

        <!--logger 日志切面拦截-->
        <aop:aspect ref="logger">

            <!--前置通知 : 在目标方法运行前加切面拦截-->
            <aop:before method="startMethod" pointcut-ref="former"/>

            <!--后置通知 获取目标方法的返回值 )-->
            <aop:after-returning method="getReturnMethod" pointcut-ref="former" returning="user"/>

            <!--最终通知 无论有无异常都执行-->
            <aop:after method="finallyMethod" pointcut-ref="former" />

            <!--异常通知  获取目标方法抛出的异常信息-->
            <aop:after-throwing method="throwMethod" pointcut-ref="former" throwing="throwable"/>

      ******************************************************************************************
      *
      *      <!--环绕通知 更为强大的通知,可以糅合 以上的通知!!! 一般单独使用
      *      如果后面还有 befor切面 则执行befor切面,再执行目标方法-->
      *      <aop:around method="aroundMethod" pointcut-ref="former"/>
      *     
      ******************************************************************************************
      
        </aop:aspect>

        <!--security 安全框架 ,一个切点可以配置多个切面-->
        <aop:aspect ref="security">
            <aop:before method="security" pointcut-ref="former"/>
        </aop:aspect>

    </aop:config>

    <!--类扫描机制-->
    <context:component-scan base-package="AOP.springaop"/>

</beans>

测试

   public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("AOP/springaop/applicationContext.xml");
        /*
         * spring AOP执行的步骤:
         * 为所有bean实例化
         * 为目标对象创建代理对象
         * 如果注入:调用set注入代理对象
         * */

        //用Service接收
//        Service service=(Service) context.getBean("serviceImp");
//        service.save();

//      此时切面绑定到service层,可以用controller接收,因为controller调用了service该代理对象
        Component component = (Component) context.getBean("component");
        component.save();
    }
}

spring-AOP注解的形式

** 各种通知的注解用法**

@Component
@Aspect //该注解说明该类是切面类
public class Method {

    /*
     *定义一个方法,用于声明切点表达式,该方法一般没有方法体
     *@Pointcut用来声明切点表达式
     *通知直接使用定义的方法名即可引入当前的切点表达式
     */
    @Pointcut("execution(* AOP.spring_aop_throw.service.userServiceImp.*(..))")
    public void former() {
    }

 //前置通知,方法执行之前执行
    @Before("former()")
    public void start(JoinPoint joinPoint) {
        System.out.println(joinPoint.getSignature().getName());  
        System.out.println("前置通知~~~~");
    }

    //后置通知,方法正常执行完毕之后执行
    @AfterReturning(value = "former() ", returning = "result")
    public void getReturnMethod(JoinPoint joinPoint, Object result) { 

        System.out.println("后置通知: " + result);
    }

    //最终通知,方法执行之后执行(不管是否发生异常)
    @After(value = "former() ")
    public void finaMethod(JoinPoint joinPoint) { 

        System.out.println("最终通知 : ~~~");
    }

    //异常通知,在方法抛出异常之后执行
    @AfterThrowing(value = "former() ", throwing = "throwable")
    public void throw1(JoinPoint joinPoint, Throwable throwable) {  
        System.out.println("异常通知:" + throwable.getMessage());
    }

Spring容器开启自动注解扫描

<?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.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">

    <!--</bean>-->
    <!--类扫描机制-->
    <context:component-scan base-package="AOP.spring_aop_throw"/>
    <!--使AspectJ注解自动为匹配的类生成代理对象-->
    <aop:aspectj-autoproxy/>
</beans>

环绕通知的用法 , 环绕通知一般单独使用

  @Around("former()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) {
        try {
            System.out.println("环绕通知:~~~~~~~");
            
            Object object = joinPoint.proceed();  //执行目标方法,返回的是该目标方法的返回值

            System.out.println("目标方法返回值 : " + object);

            return object;  //需要重新将目标连接点的返回值返回出去
        } catch (Throwable throwable) {

            throwable.printStackTrace();
            return "flase";
        }
    }

JoinPoint 用法

能够调用该API得到连接点的一些信息, JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
-在这里插入图片描述

ProceedingJoinPoint

(程序连接点 :客户端代理对象调用哪个方法,哪个方法就是连接点)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值