SSM中的Spring框架AOP实操(第九课)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: SSM中的Spring框架AOP实操(第九课)

第一部分:Spring配置文件applicationContext.xml文件写Aop的三种方式:

本博文是来对SpringAop中三种方式的回顾的

SpringAop的理论概念

1、什么是aop:

AOP(Aspect Oriented Programming)称为面向切面编程,在程序开发中主要用来解决一些系统层面上的问题,比如日志,事务,权限等待,Struts2的拦截器设计就是基于AOP的思想,是个比较经典的例子。


在不改变原有的逻辑的基础上,增加一些额外的功能。代理也是这个功能,读写分离也能用aop来做。


AOP可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。


AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。


使用"横切"技术,AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

2、AOP的相关概念:

(1)横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

(2)Aspect(切面):通常是一个类,里面可以定义切入点和通知

(3)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用。被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

(4)Advice(通知):AOP在特定的切入点上执行的增强处理,有before(前置),after(后置),afterReturning(最终),afterThrowing(异常),around(环绕)

(5)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

(6)weave(织入):将切面应用到目标对象并导致代理对象创建的过程

(7)introduction(引入):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

(8)AOP代理(AOP Proxy):AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

(9)目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。POJO

3、Advice通知类型介绍:

(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可


(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值


(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名


来访问目标方法中所抛出的异常对象


(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式


(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint

4、AOP使用场景:

Authentication 权限

Caching 缓存

Context passing 内容传递

Error handling 错误处理

Lazy loading 懒加载

Debugging  调试

logging, tracing, profiling and monitoring 记录跟踪 优化 校准

Performance optimization 性能优化

Persistence  持久化

Resource pooling 资源池

Synchronization 同步

Transactions 事务

5 注解的方式开发 Aop

在XML配置文件中对Bean的注册  

<bean id="userservice" class="com.service.UserServiceImp"></bean>
    <bean id="Car" class="com.service.CarImp"></bean>
    <bean id="Dog" class="com.service.DogImp"></bean>
    <bean id="Firsh" class="com.service.FirshImp"></bean>
    <bean id="Pig" class="com.service.PigImp"></bean>
    <bean id="log" class="log.Log"></bean>
    <bean id="afterlog" class="log.Afterlog"></bean>

在配置文件中写上注解的方式

方案一 注解的方式

    <!--&lt;!&ndash;方式三 SpringAop的注解的方式&ndash;&gt;-->
        <bean id="annotationPointCut" class="diy.AnnotationPointCut"></bean>
        <!--代理Aop注解支持 JDK  proxy-target-class="false" -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <bean id="annotationPointCut" class="diy.DogAnnotationPointCut"></bean>
    <!--代理Aop注解支持 JDK  proxy-target-class="false" -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

自己创建一个类在类中写关于SpringAop注解

package diy;
import com.sun.istack.internal.NotNull;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.service.UserServiceImp.*(..))")
    public void before() {
        System.out.println("==============方法执行前=================");
    }
    @After("execution(* com.service.UserServiceImp.*(..))")
    public  void  seeyou(){
        System.out.println("游湖调用的seeyou方法");
    }
    @After("execution(* com.service.UserServiceImp.*(..))")
    public void after() {
        System.out.println("==============方法执行后==================");
    }
    @Around("execution(* com.service.UserServiceImp.*(..))")
    public  void  around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("在环绕增强中,我们可以定义一个参数,代表我们要获取处理的切入点");
        Object o = jp.proceed();
        System.out.println("环绕前");
    }
}
package diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class DogAnnotationPointCut {
    @Before("execution(* com.service.DogImp.*(..))")
    public void before() {
        System.out.println("==============方法执行前=================");
    }
    @After("execution(* com.service.DogImp.*(..))")
    public  void  seeyou(){
        System.out.println("游湖调用的seeyou方法");
    }
    @After("execution(* com.service.DogImp.*(..))")
    public void after() {
        System.out.println("==============方法执行后==================");
    }
    @Around("execution(* com.service.DogImp.*(..))")
    public  void  around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("在环绕增强中,我们可以定义一个参数,代表我们要获取处理的切入点");
        Object o = jp.proceed();
        System.out.println("环绕前");
    }
}

6 自定义实体类的方式开发SpringAop在北至文件中书写的内容


方案二 自定义实体类

<!--    SpringAop的方案二 Class:要在那个类中去定义实体呢-->
        <bean id="diy" class="diy.DiyPointcut"></bean>
        <aop:config>
            <!--自定义切面 ref 要自定义实体类的包名-->
            <aop:aspect ref="diy">
                <!--切入点 实现类的方法在哪里 -->
               <aop:pointcut id="point" expression="execution(* com.service.UserServiceImp.*(..)))"/>
                <!--通知将自己定义的方法定义到本类中来-->
                <aop:before method="before" pointcut-ref="point"></aop:before>
                <aop:after method="after" pointcut-ref="point"></aop:after>
                <aop:after method="see" pointcut-ref="point"></aop:after>
            </aop:aspect>
        </aop:config>

自己创建一个类在类中写关于SpringAop 方法

package diy;
/**
 * 自定义类
 */
public class DiyPointcut {
    public  void  before(){
        System.out.println("==============方法执行前=================");
    }
    public  void  after(){
        System.out.println("==============方法执行后==================");
    }
    /**
     * 在配置文件中注册方法
     */
    public  void  see(){
        System.out.println("===========SpringAOP第二种方式自定义类的方式=============");
    }
}

7 原始方案 SpringAop

package log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class Afterlog  implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"返回了"+o1);
    }
}
package log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log  implements MethodBeforeAdvice {
    //Method 要执行的目标对象方法
    //orgs  参数
    //target 目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}

方案三:原始方案

<!--Car的注册-->
    <aop:config>
        <!--切入点  execution表达式( 要执行的位置! * * * *)-->
        <aop:pointcut id="pointcut" expression="execution(* com.service.CarImp.*(..))"/>
        <!--执行环绕增加-->
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
        <aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>

第二部分代码测试:

import com.service.*;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MaTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    //动态代理的是接口
        UserService userservice = (UserService) applicationContext.getBean("userservice");
        userservice.update();
        System.out.println("==============================================================");
        //Car测试
        Car car =(Car) applicationContext.getBean("Car");
        car.run();
    //   Dog测试
        System.out.println("==============================================================");
        Dog dog=(Dog) applicationContext.getBean("Dog") ;
        dog.eat();
        dog.update();
        System.out.println("==============FirshImp=====================");
    //Firsh测试
        Firsh firsh=(Firsh) applicationContext.getBean("Firsh");
        firsh.update();
    }
}

8 代码模块

Car类:

package com.service;
public class CarImp implements Car {
    @Override
    public void add() {
        System.out.println("增加一条记录在Car在Car表中");
    }
    @Override
    public void delete() {
    }
    @Override
    public void update() {
    }
    @Override
    public void query() {
    }
    @Override
    public void X() {
    }
    @Override
    public void run() {
        System.out.println("Car在run中奔跑在Car的类中");
    }
}

Dog类:

package com.service;
public class DogImp  implements Dog{
    @Override
    public void eat() {
        System.out.println("DogImp在吃食物");
    }
    @Override
    public void add() {
        System.out.println("DogImp在吃食物在增加记录");
    }
    @Override
    public void delete() {
        System.out.println("DogImp在删除信息");
    }
    @Override
    public void update() {
        System.out.println("DogImp在修改信息");
    }
    @Override
    public void query() {
    }
    @Override
    public void X() {
    }
}

Firsh类:

标题

package com.service;
public class FirshImp  implements Firsh{
    @Override
    public void swwing() {
        System.out.println("FirshIm在Swwing游泳");
    }
    @Override
    public void add() {
        System.out.println("FirshImp增加的操作");
    }
    @Override
    public void delete() {
        System.out.println("FirshImp删除的操作");
    }
    @Override
    public void update() {
        System.out.println("FirshImp修改的操作");
    }
    @Override
    public void query() {
    }
    @Override
    public void X() {
    }
}

Pig类

package com.service;
public class PigImp implements pig {
    @Override
    public void sleep() {
        System.out.println("PigImp自己最喜欢睡觉");
    }
    @Override
    public void add() {
        System.out.println("用户开始从某某数据库中的表中增加了一个用户记录");
    }
    @Override
    public void delete() {
        System.out.println("用户开始从某某数据库中的表中删除了一个用户");
    }
    @Override
    public void update() {
        System.out.println("用户开始从某某数据库中的表中修改了一条记录");
    }
    @Override
    public void query() {
        System.out.println("用户开始从某某数据库中的表中查询用户多条信息和单条记录");
    }
    @Override
    public void X() {
        System.out.println("本人自定义的方法为X()方法");
    }
    @Override
    public void pigpig() {
        System.out.println("PigImp自己独有的方法构造");
    }
}

UserService类:

package com.service;
public interface UserService {
    //在 UserService定义 增删改查的方法 来构造
    public  void  add();
    public  void  delete();
    public  void  update();
    public  void  query();
    public  void X();
}
package com.service;
public class UserServiceImp  implements UserService{
    /**
     *  UserServiceImp  implements UserService
     *  在这个类中实现UserService中没有实现的方法
     */
    @Override
    public void add() {
        System.out.println("用户开始从某某数据库中的表中增加了一个用户记录");
    }
    @Override
    public void delete() {
        System.out.println("用户开始从某某数据库中的表中删除了一个用户");
    }
    @Override
    public void update() {
        System.out.println("用户开始从某某数据库中的表中修改了一条记录");
    }
    @Override
    public void query() {
        System.out.println("用户开始从某某数据库中的表中查询用户多条信息和单条记录");
    }
    @Override
    public void X() {
        System.out.println("本人自定义的方法为X()方法");
    }
}
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
15天前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
31 4
|
17天前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
98 1
|
12天前
|
Java API 数据库
Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐
本文通过在线图书管理系统案例,详细介绍如何使用Spring Boot构建RESTful API。从项目基础环境搭建、实体类与数据访问层定义,到业务逻辑实现和控制器编写,逐步展示了Spring Boot的简洁配置和强大功能。最后,通过Postman测试API,并介绍了如何添加安全性和异常处理,确保API的稳定性和安全性。
26 0
|
6天前
|
前端开发 Java 数据库连接
Spring 框架:Java 开发者的春天
Spring 框架是一个功能强大的开源框架,主要用于简化 Java 企业级应用的开发,由被称为“Spring 之父”的 Rod Johnson 于 2002 年提出并创立,并由Pivotal团队维护。
23 1
Spring 框架:Java 开发者的春天
|
12天前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
24 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
6天前
|
Java 数据库连接 开发者
Spring 框架:Java 开发者的春天
【10月更文挑战第27天】Spring 框架由 Rod Johnson 在 2002 年创建,旨在解决 Java 企业级开发中的复杂性问题。它通过控制反转(IOC)和面向切面的编程(AOP)等核心机制,提供了轻量级的容器和丰富的功能,支持 Web 开发、数据访问等领域,显著提高了开发效率和应用的可维护性。Spring 拥有强大的社区支持和丰富的生态系统,是 Java 开发不可或缺的工具。
|
12天前
|
人工智能 开发框架 Java
总计 30 万奖金,Spring AI Alibaba 应用框架挑战赛开赛
Spring AI Alibaba 应用框架挑战赛邀请广大开发者参与开源项目的共建,助力项目快速发展,掌握 AI 应用开发模式。大赛分为《支持 Spring AI Alibaba 应用可视化调试与追踪本地工具》和《基于 Flow 的 AI 编排机制设计与实现》两个赛道,总计 30 万奖金。
|
13天前
|
人工智能 Java API
阿里云开源 AI 应用开发框架:Spring AI Alibaba
近期,阿里云重磅发布了首款面向 Java 开发者的开源 AI 应用开发框架:Spring AI Alibaba(项目 Github 仓库地址:alibaba/spring-ai-alibaba),Spring AI Alibaba 项目基于 Spring AI 构建,是阿里云通义系列模型及服务在 Java AI 应用开发领域的最佳实践,提供高层次的 AI API 抽象与云原生基础设施集成方案,帮助开发者快速构建 AI 应用。本文将详细介绍 Spring AI Alibaba 的核心特性,并通过「智能机票助手」的示例直观的展示 Spring AI Alibaba 开发 AI 应用的便利性。示例源
|
16天前
|
Java 数据库连接 数据库
让星星⭐月亮告诉你,SSH框架01、Spring概述
Spring是一个轻量级的Java开发框架,旨在简化企业级应用开发。它通过IoC(控制反转)和DI(依赖注入)降低组件间的耦合度,支持AOP(面向切面编程),简化事务管理和数据库操作,并能与多种第三方框架无缝集成,提供灵活的Web层支持,是开发高性能应用的理想选择。
21 1