SpringAop的理解以及实现原理

AOP的概念:

Aop即面向切面编程,是对oop的一种补充和完善,在oop中有大量重复代码,不利于各个模块的重用,Aop采用一种叫做”横切“的技术,剖解开封装的对象内部,并将那些公共行为封装到一个可重用模块,并将其命名为“Aspect",即切面。

  1. Aspect(切面):封装了共性方法的类,里面可以定义切入点和通知,是对横切关注点的抽象。
  2. Pointcut(切入点):带有通知的连接点,用一个表达式来提现
  3. Advice(通知):增强功能的一些方法,包含before,after,afterReturning,afterThrowing,around
  4. JoinPoint(连接点): 程序执行过程中明确的点,一般是方法的调用,常作为方法的形参。
  5. Waving(织入):将切面应用到目标对象并导致产生代理对象的过程。

第一种:使用配置文件application-aop.xml

直接上代码,定义一个业务逻辑类:

package com.daling.config.springAop.aop.service;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
@Service
public class MemberService {
    private final static Logger log = Logger.getLogger(MemberService.class);
    
    public void add(){
        System.out.println("======================================添加会员");
    }
    public void remove(Integer id) throws Exception{
        System.out.println("======================================删除会员");
        throw new Exception("这是我们自己抛出的异常");
    }
    public void update(Integer id){
        System.out.println("======================================更改会员");
    }
    public void query(Integer id){
        System.out.println("======================================查询会员");
    }
}

定义一个切面类:

package com.daling.config.springAop.aop.aspect;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;

public class LoginAspect {
    private final static Logger log = Logger.getLogger(LoginAspect.class);

    public void before(JoinPoint joinpoint){
        log.info("======================================调用方法之前执行" + joinpoint);
    }
    public void after(JoinPoint joinpoint){
        log.info("======================================调用方法之后执行" + joinpoint);
    }
    public boolean afterReturn(JoinPoint joinpoint){
        log.info("======================================调用方法返回之前执行" + joinpoint);
        return true;
    }
    public void afterThrow(JoinPoint joinpoint){
        log.info("======================================抛出异常之后执行" + joinpoint);
    }
}

application-aop.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:p="http://www.springframework.org/schema/p"
        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/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 开启注解扫描-->
    <context:component-scan base-package="com.daling.config.springAop.aop"></context:component-scan>

    <!--aop自动代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <!--声明一个需要织入到虚拟切面的切面-->
    <bean id="logAspect" class="com.daling.config.springAop.aop.aspect.LoginAspect"></bean>
    <aop:config>
        <!--声明切入点,id用来标记这个切入点; expresssion: 满足expression中的方法调用之后,就会去进行切面操作,类似于触发了切面
                 第一个* 代表返回任意类型 ,
                 第一个.. 所有的子包
                 * 方法名任意
                 第二个.. 表示方法的参数是任意数量和类型
         -->
        <aop:pointcut id="logPointcut" expression="execution(* com.daling.config.springAop.aop.service..*(..))" ></aop:pointcut>
        <!--
            简单说就是,只要com.daling.config.springAop.aop.service这个包中的所有子包,以及包下的所有类的任意一个函数被调用,不管你的返回值是什么,都会触发开关,
            我就会去执行切面,也就是辅助功能,但是辅助功能是什么呢,就是下面两句:
        -->
        <aop:aspect id="" ref="logAspect">
            <aop:before method="before" pointcut-ref="logPointcut"></aop:before>
            <aop:after method="after" pointcut-ref="logPointcut"></aop:after>
            <aop:after-returning method="afterReturn" returning="boolean" pointcut-ref="logPointcut"></aop:after-returning>
            <aop:after-throwing method="afterThrow" pointcut-ref="logPointcut"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
</beans>

测试类进行测试:

package com.daling.test;


import com.daling.config.springAop.aop.service.MemberService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(locations = {"classpath:config/application-aop.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class AopTest {
    @Autowired
    private MemberService memberService;
    @Test
    public void testAdd(){
        memberService.add();
    }
    @Test
    public void testRemove(){
        try {
            memberService.remove(1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Test
    public void testUpdate(){
        memberService.update(1);
    }
    @Test
    public void testQuery(){
        memberService.query(1);
    }
}

测试结果:
在这里插入图片描述

第二种:使用注解

MemberService类不变,切面类改为如下类:

package com.daling.config.springAop.aop.aspect;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component  //实现自动注入
@Aspect     //声明该类为切面类
public class AnnotationAspect {
    //Waving(织入):将切面应用到目标对象并导致代理对象创建的过程
    private final static Logger log = Logger.getLogger(AnnotationAspect.class);

    /**
     *  声明一个切入点: 带有通知的连接点,在程序上体现为切入点表达式
     *  expresssion: 满足expression中的方法调用之后,就会去进行切面操作,类似于触发了切面
     */
    @Pointcut("execution(* com.daling.config.springAop.aop.service..*(..))")
    public void pointCutConfig(){}

    /**
     * Advice:通知 aop在特定的切入点上执行的增强处理,包含before,after,afterReturning,afterThrowing,around
     * @param joinpoint
     */
    @Before("pointCutConfig()")
    public void before(JoinPoint joinpoint){//JoinPoint:连接点
        log.info("======================================调用方法之前执行" + joinpoint);
    }
    @After("pointCutConfig()")
    public void after(JoinPoint joinpoint){
        log.info("======================================调用方法之后执行" + joinpoint);
    }
    @AfterReturning("pointCutConfig()")
    public boolean afterReturn(JoinPoint joinpoint){
        log.info("======================================调用方法返回之前执行" + joinpoint);
        return true;
    }
    @AfterThrowing("pointCutConfig()")
    public void afterThrow(JoinPoint joinpoint){
        System.out.println("切点的参数:" + Arrays.toString(joinpoint.getArgs()));
        System.out.println("切点的方法:" + joinpoint.getSignature());
        System.out.println("生成以后的代理对象: " + joinpoint.getTarget());//生成以后的代理对象
        System.out.println("this: " + joinpoint.getThis());//当前类的本身(反射调用)
        log.info("======================================抛出异常之后执行" + joinpoint);
    }
}

配置文件开启注解扫描和aop自动代理不能少:

<?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:p="http://www.springframework.org/schema/p"
        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/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 开启注解扫描-->
    <context:component-scan base-package="com.daling.config.springAop.aop"></context:component-scan>
    <!--aop自动代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

测试类不变:结果如下,测试remove()方法
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值