Spring的核心AOP及代理模式(“最易懂得Spring学习”)

Posted 奔走的王木木Sir

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring的核心AOP及代理模式(“最易懂得Spring学习”)相关的知识,希望对你有一定的参考价值。

🏇 哇 咔 咔 : \\textcolorblue哇咔咔: 在 前 两 篇 中 我 们 了 解 了 I O C \\textcolorgreen在前两篇中我们了解了IOC IOC
🏇 接 下 来 就 接 触 一 下 另 一 个 核 心 A O P \\textcolorpink接下来就接触一下另一个核心AOP AOP
💥所用到的代码都可以在这里找到💥
🙏 博 主 也 在 学 习 阶 段 , 如 若 发 现 问 题 , 请 告 知 , 非 常 感 谢 \\textcolorOrange博主也在学习阶段,如若发现问题,请告知,非常感谢 💗

🐳点击送你到《简单了解了Spring以及IOC的理论推导》
🐳点击送你到《Spring中的IOC和DI》

AOP

1. 什么是AOP

​ AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的同一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低提高程序的可重用性,同时提高了开发的效率

A O P 的 主 要 功 能 \\textcolororangeAOP的主要功能 AOP

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

Spring AOP切面简单理解就是一把刀,在执行过程中可以随意地插入或拔出。

2. Aop在Spring中的作用

提供声明式事务;允许用户自定义切面

  • 横切关注点:对哪写方法进行拦截,拦截后又怎么处理,与我们业务逻辑无关的,但我们需要关注的部分,就是横切关注点,如日志,安全,缓存,事务等。跨越应用程序多个模块的方法或功能。
  • 切面(ASPECT):横切关注点被模块化的特殊对象,即它是一个类
  • 通知(Advice):切面必须要完成的工作,即它是类中的一个方法
  • 目标(Target):被通知对象,也就是代理的目标对象。
  • 代理(Proxy):向目标对象应用通知后创建的对象。
  • 切入点(PointCut):切面通知执行的”地点“的定义
  • 连接点(JointPoint):与切入点匹配的执行点。
  • 织入(weave):将切面应用到目标对象并导致代理对象创建的过程。

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice

3. 使用Spring实现AOP

【重点】使用AOP织入,需要导入一个依赖包

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.7</version>
    </dependency>
</dependencies>

方式一:使用Spring的api接口[主要是api接口]

UserService

package com.hxl.service;

public interface UserService 
    public void add();
    public void delete();
    public void update();
    public void select();

UserServiceImpl

package com.hxl.service;

public class UserServiceImpl implements UserService
    public void add() 
        System.out.println("增加了一个用户");
    

    public void delete() 
        System.out.println("删除了一个用户");
    

    public void update() 
        System.out.println("修改了一个用户");
    

    public void select() 
        System.out.println("查询了一个用户");
    

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/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">

    <!--注册bean-->
    <bean id="userService" class="com.hxl.service.UserServiceImpl"/>
    <bean id="log" class="com.hxl.log.Log"/>
    <bean id="afterLog" class="com.hxl.log.LogAfter"/>

    <!--使用原生的Spring API接口-->
    <!--配置aop:需要导入aop的约束-->
    <aop:config>
        <!--切入点;expression:表达式,execution(要执行的位置,修饰词,返回值,类名,方法名,参数)-->
        <aop:pointcut id="pointCut" expression="execution(* com.hxl.service.UserServiceImpl.*(..))"/>
        <!--执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointCut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointCut"/>
    </aop:config>
</beans>

测试:

import com.hxl.service.UserService;
import com.hxl.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest 
    public static void main(String[] args) 
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //注意点:动态代理代理的是接口
        UserService userService = context.getBean("userService", UserService.class);
        userService.add();
    

方式二:自定义来实现aop[主要是切面]

DiyPointCut

package com.hxl.diy;

public class DiyPointCut 
    public void before()
        System.out.println("====方法执行前====");
    
    public void after()
        System.out.println("====方法执行后====");
    

<!--方式二:自定义类-->
<bean id="diy" class="com.hxl.diy.DiyPointCut"/>
<aop:config>
    <!--自定义切面,ref要引用的类-->
    <aop:aspect ref="diy">
        <!--切入点-->
        <aop:pointcut id="point" expression="execution(* com.hxl.service.UserServiceImpl.*(..))"/>
        <!--通知-->
        <aop:before method="before" pointcut-ref="point"/>
        <aop:after method="after" pointcut-ref="point"/>
    </aop:aspect>
</aop:config>

方式三:使用注解来实现aop

package com.hxl.diy;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

//方式三:使用注解方式实现aop
@Aspect//标注这个类是一个切面
public class AnnotationPointCut 
    @Before("execution(* com.hxl.service.UserServiceImpl.*(..))")
    public void before()
        System.out.println("====方法执行前====");
    
    @After("execution(* com.hxl.service.UserServiceImpl.*(..))")
    public void after()
        System.out.println("====方法执行后====");
    
    //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
    @Around("execution(* com.hxl.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable 
        System.out.println("====环绕前====");
        Signature signature = jp.getSignature();//获得签名
        System.out.println("signature:" + signature);
        //执行方法
        Object proceed = jp.proceed();
        System.out.println("=====环绕后====");
    

<!--方式三:-->
<bean id="annotationPointCut" class="com.hxl.diy.AnnotationPointCut"/>
<!--开启注解支持
    JDK(默认proxy-target-class="false")
    cglib(proxy-target-class="true")
    -->
<aop:aspectj-autoproxy />

代理模式

为什么要学习代理模式?因为这是SpringAOP的底层

面试的过程中会问【SpringAOP和ApringMVC】

代理模式分为:静态代理和动态代理

1. 静态代理

1.1 初次理解

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理后一般会有一些附属操作
  • 客户:访问代理对象的人!

代码步骤

  1. 接口

    package com.hxl.demo01;
    
    //租房
    public interface Rent 
        public void rent();
    
    
    
  2. 真实角色

    package com.hxl.demo01;
    
    //房东
    public class Host implements Rent
    
        public void rent() 
            System.out.println("房东要出租房子");
        
    
    
  3. 代理角色

    package com.hxl.demo01;
    
    public class Proxy implements Rent
        private Host host;
    
        public Proxy() 
        
    
        public Proxy(Host host) 
            this.host = host;
        
    
        public void rent() 
            seeHouse();
            host.rent();
            contract();
            fare();
        
        //看房
        public void seeHouse()
            System.out.println("中介带你取看房");
        
        //签合同
        public void contract ()
            System.out.println("签租赁合同");
        
        //收中介费
        public void fare()
            System.out.println("收中介费");
        
    
    
  4. 客户端访问代理角色

    package com.hxl.demo01;
    
    public class Client 
        public static void main(String[] args) 
            Host host = new Host();
            //代理,中介帮房东租房,代理角色一般会有一些附属操作
            Proxy proxy = new Proxy(host);
            //不用面对房东,直接找中介租房
            proxy.rent();
        
    
    

代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不用取关注一些公共的业务
  • 公共业务交给代理角色,实现业务的分工
  • 公共业务发生扩展的时候,方便集中管理

代理模式的缺点:

  • 一个真实角色就会产生一个代理角色
  • 代码量会翻倍,开发效率会变低

1.2 再次理解

package com.hxl.demo02;

public interface UserService 
    public void add();
    public void delete();
    public void update();
    public void query();

package com.hxl.demo02;

//真实对象
public class UserServiceImpl implements UserService
    public void add() 
        System.out.println("增加了一个用户");
    

    public void delete() 
        System.out.println("删除了一个用户");
    

    public void update() 
        System.out.println("修改了一个用户");
    

    public void query() 
        System.out.println("查询了一个用户");
    

package com.hxl.demo02;

public class UserServiceProxy implements UserService
    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) 
        this.userService = userService;
    

    public void add() 
        log("add");
        userService.add();
    

    public void delete() 
        log("delete");
        userService.delete();
    

    public void update() 
        log("update");
        userService.update();
    

    public void query() 
        log("query");
        userService.query();
    
    //日志方法
    public void log(String msg)
        System.out.println("[日志输出]使用了" + msg + "方法")以上是关于Spring的核心AOP及代理模式(“最易懂得Spring学习”)的主要内容,如果未能解决你的问题,请参考以下文章

Spring之AOP(核心思想:代理模式)

如何使用Proxy模式及Java内建的动态代理机制

深入浅出Spring原理及实战「原理分析专题」不看源码就带你剖析AOP容器核心流程以及运作原理

学习Spring

学习Spring

学习Spring