spring学习总结013 --- AOP面向切面编程

AOP能够在应用程序指定位置、指定时机,植入指定功能,并且不影响原程序的功能;

最简单的而举例:在已有应用程序的所有方法调用前后分别添加日志;我们肯定不能修改程序,在每个方法前后添加日志,这样做工作量大,容易遗漏,更重要的是违背了“开闭原则”

AOP面向切面编程不是spring框架独有的,其他比较著名的框架是AspectJ;我们常说的spring AOP是spring整合和AspectJ,当然spring自身也实现了AOP,不过比较厚重(在spring事务中有应用)

一些基本概念

  • 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
  • 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
  • 切点(PointCut): 可以插入增强处理的连接点。
  • 切面(Aspect): 切面是通知和切点的结合。
  • 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
  • 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织

这些概念比较抽象,需要在实际应用中理解

spring AOP实例(注解方式)

1、添加maven依赖:spring-aop、spring-aspects、spring-context

2、创建spring配置类

@Configuration // 声明为spring配置类
@ComponentScan(basePackages = {"com.demo"}) // 扫描com.demo包下的bean定义
@EnableAspectJAutoProxy // 为切面类创建代理, 植入增强
public class AopConfig {
}

3、定义切面

@Slf4j
@Aspect // 声明为切面
@Component
public class LogAspect {

    // 定义切点及切点表达式, 即声明在哪些方法织入切面
    @Pointcut("execution(public void com.demo.service.*.*(*))")
    public void pointcut() {
    }

    @Before("pointcut()") // 织入前置通知
    public void before(JoinPoint joinPoint) {
        log.info("Before invoke method:{}", joinPoint.getSignature().getName());
    }
}

4、业务代码,spring会使用CGLIB为该类生成代理类

@Service
public class AopService {

    public void func1(String name) {
        log.info("================Invoke func1, name:{}================", name);
    }
}

5、测试代码

    @Test
    public void test_cglib_proxy() {
        AopService aopService = applicationContext.getBean(AopService.class);
        aopService.func1("bale");
        log.info("AopService class:{}", aopService.getClass().getName());
    }

执行结果:

前面的业务代码采用CGLIB创建代理类,如果想采用JDK方式创建代理类,那么需要业务方法为接口实现类,举例如下:

接口:

public interface AopServiceIntf {
    public void printSomething(String name);
}

实现类:

@Slf4j
@Component
public class AopServiceIntfImpl implements AopServiceIntf {

    @Override
    public void printSomething(String name) {
        log.info("=====================Invoke printSomething, name:{}====================", name);
    }
}

测试类:

    @Test
    public void test_jdk_proxy() {
        AopServiceIntf aopServiceIntf1 = (AopServiceIntf) applicationContext.getBean("aopServiceIntfImpl");
        aopServiceIntf1.printSomething("bale1");
        log.info("AopServiceIntf1 class:{}", aopServiceIntf1.getClass().getName());
    }

执行结果:

spring AOP实例(XML配置方式)

1、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/context
       https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.demo" />

    <aop:aspectj-autoproxy />

    <bean class="com.demo.aop.LogXmlAspect" id="logXmlAspect" />

    <aop:config>
        <aop:aspect id="logAspect" ref="logXmlAspect">
            <aop:pointcut id="logPointcut" expression="execution(public void com.demo.service.*.*(*))"/>
            <aop:before method="before" pointcut-ref="logPointcut" />
        </aop:aspect>
    </aop:config>
</beans>

2、切面类

@Slf4j
public class LogXmlAspect {

    public void before(JoinPoint joinPoint) {
        log.info("Before invoke method:{}", joinPoint.getSignature().getName());
    }
}

3、同样的测试类和业务类,执行结果:

 

指定代理方式

<aop:aspectj-autoproxy proxy-target-class="true" />

proxy-target-class="true"表示使用CGLIB代理方式

proxy-target-class="false"为默认值,如果委托类为接口实现类则使用JDK代理方式,否则采用CGLIB代理方式

posted @ 2020-07-16 11:47  光头用沙宣  阅读(175)  评论(0编辑  收藏  举报