Springboot中的IOC与AOP

1.IOC

1.1 IOC

Spring Boot 的 IOC(Inversion of Control,控制反转)是 Spring 框架的核心特性之一,旨在降低代码之间的耦合度,提高系统的可维护性和可扩展性。在 Spring Boot 中,IOC 的主要实现方式是依赖注入(Dependency Injection,DI)。
控制反转(IOC)
控制反转是一种设计原则,其核心思想是:将原本由代码直接操控的对象的调用权交给第三方(例如一个容器)来控制,以解耦代码,提高程序的可扩展性和可维护性。
依赖注入(DI)
依赖注入是实现控制反转的一种手段。在 Spring Boot 中,你可以通过构造器、Setter 方法或字段注入的方式,将依赖的对象注入到需要它的类中。这样,你就可以在运行时动态地改变对象之间的依赖关系,而不需要修改源代码。

1.2 示例

数据库连接信息:

package org.example;
import lombok.Data;

@Data
public class DataConfig {
    private String host;
    private String port;
    private String username;
    private String password;
}

1.2.1 配置文件

配置文件:

<?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:util="http://www.springframework.org/schema/util"
       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/util
                        http://www.springframework.org/schema/util/spring-util-4.0.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 class="org.example.DataConfig" id="dataConfig">
        <property name="host" value="localhost"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="port" value="3306"/>

    </bean>
</beans>

配置IOC容器:

//读取xml配置文件配置IOC容器
ApplicationContext xmlcontext=new ClassPathXmlApplicationContext("spring.xml");
DataConfig xmldataConfig = (DataConfig) context.getBean("dataConfig");
System.out.println(xmldataConfig.getHost());

1.2.2 配置类

新建Bean配置类:

package org.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfiguration {

    //设置参数:@Bean(name = "config")
    @Bean
    public DataConfig dataConfig(){
        DataConfig dataConfig = new DataConfig();
        dataConfig.setHost("localhost");
        dataConfig.setPort("3306");
        dataConfig.setUsername("root");
        dataConfig.setPassword("root");
        return dataConfig;
    }
}

格局配置类创建IOC容器:

//读取配置类配置IOC容器
ApplicationContext context = new AnnotationConfigApplicationContext(BeanConfiguration.class);
DataConfig dataConfig = context.getBean(DataConfig.class);
System.out.println(dataConfig.getHost());

读取配置包导入IOC容器:

//读取配置包配置IOC容器
ApplicationContext ctx=new AnnotationConfigApplicationContext("org.example.config");
DataConfig dataConfig1 = ctx.getBean(DataConfig.class);
System.out.println(dataConfig1.getHost());

1.2.3 扫包+注解

扫包,如把DataConfig类放入包:"org.example.dataconfig":

ApplicationContext context = new AnnotationConfigApplicationContext("org.example.dataconfig");
DataConfig dataConfig = context.getBean(DataConfig.class);
System.out.println(dataConfig.getHost());

注解,对DataConfig类添加@Component注解,使用@Value设置值:

package org.example.dataconfig;

import lombok.Data;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;

@Data
@Component
public class DataConfig {
    @Value("localhost")
    private String host;
    @Value("3306")
    private String port;
    @Value("root")
    private String username;
    @Value("root")
    private String password;
}

1.3 依赖注入:自动装配

使用:

ApplicationContext context = new AnnotationConfigApplicationContext("org.example.dataconfig");
GlobalConfig config= context.getBean(GlobalConfig.class);
System.out.println(config);

新建GLobalConfig类,对于DataConfig使用@Autowired进行自动装载:

package org.example.dataconfig;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Data
@Component
public class GlobalConfig {
    @Value("/home/user/data")
    private String path;
    @Autowired
    private DataConfig dataConfig;
}

2.AOP

2.1 AOP

Spring Boot AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架的一个关键组件,它允许开发者定义横切关注点(cross-cutting concerns),并将这些关注点与业务逻辑代码分离。横切关注点通常包括日志记录、事务管理、安全性、性能监控等,这些功能通常会跨越多个类和方法,如果直接在业务逻辑代码中实现,会导致代码冗余和难以维护。
AOP 通过将关注点模块化到切面(Aspect)中,并将切面与业务逻辑代码通过连接点(Join Point)进行关联,从而实现了关注点与业务逻辑的解耦。
在 Spring Boot 中,AOP 的实现主要依赖于 Spring AOP 和 AspectJ。Spring AOP 是 Spring 框架自带的 AOP 实现,它基于代理模式;而 AspectJ 是一个独立的 AOP 框架,提供了更强大和灵活的 AOP 功能。Spring Boot 可以与 AspectJ 集成,以支持更复杂的 AOP 需求。

2.2 示例

2.2.1 使用

计算加减:

package org.example.ioc;

import org.springframework.stereotype.Component;

@Component
public class Calc {

    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }
}

配置文件:

<?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:util="http://www.springframework.org/schema/util"
       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/util
                        http://www.springframework.org/schema/util/spring-util-4.0.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="org.example.ioc"/>

<!--        配置动态代理-->
        <aop:aspectj-autoproxy/>
</beans>

日志打印切面类:

package org.example.ioc;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class Logger {

    @Before("execution(* org.example.ioc.Calc.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Before method execution: " + methodName+"  params:"+joinPoint.getArgs()[0]+"  "+joinPoint.getArgs()[1]);
    }

    @AfterReturning(pointcut = "execution(* org.example.ioc.Calc.*(..))", returning = "result")
    public void logAfter(JoinPoint joinPoint,Object result) {
        System.out.println("After method executio: "+joinPoint.getSignature().getName()+"  result:"+result);
    }

}

使用:

ApplicationContext iocontext = new ClassPathXmlApplicationContext("aop.xml");
Calc calc = iocontext.getBean(Calc.class);
System.out.println(calc.add(1,2));

结果:

Before method execution: add  params:1  2
After method executio: add  result:3
3

2.2.2 SpringBoot项目日志

package com.example.videoplay.utils;

import com.example.videoplay.service.LogService;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
@EnableAsync
@Aspect
public class LoggerAspect {

    @Autowired
    private LogService logService;

    @Before("execution(* com.example.videoplay.controller.VideoController.delayVideo(..))" +
            " || execution(* com.example.videoplay.controller.VideoController.getVideoList(..)) ")
    public void videoBefore(JoinPoint joinpoint) {
        HttpServletRequest request=(HttpServletRequest)joinpoint.getArgs()[0];
        String method=joinpoint.getSignature().getName(); //函数名称
        try {
            Map<String, String> map = (Map<String, String>) joinpoint.getArgs()[1];
            String ipaddress = map.get("ip") == null ? request.getRemoteAddr() : map.get("ip"); //ip地址
            insertLog(Integer.valueOf(map.get("userId")), map.toString(), method, ipaddress);
        }catch (Exception e) {
            System.out.println("video log failed");
        }
    }

    @Before("execution(* com.example.videoplay.controller.VideoController.getVideo(..)) " +
            "|| execution(* com.example.videoplay.controller.VideoController.getM3U8Content(..))")
    public void playVideoBefore(JoinPoint joinpoint) {
        HttpServletRequest request=(HttpServletRequest)joinpoint.getArgs()[0];
        String method=joinpoint.getSignature().getName();
        Map<String,String> map=new HashMap<>();
        map.put("filename",request.getParameter("filename"));
        map.put("id",request.getParameter("id"));
        map.put("token",request.getParameter("token"));
        map.put("ip",request.getParameter("ip"));
        String ipaddress=map.get("ip")==null?request.getRemoteAddr():map.get("ip"); //ip地址
        String token=map.get("token");
        try {
            Map<String, Object> tokenMap= JwtUtils.verifyJWT(token);
            insertLog((int) tokenMap.get("id"),map.toString(),method,ipaddress);
        }catch (Exception e) {
            System.out.println("token verify failed");
        }
    }

    @Before("execution(* com.example.videoplay.controller.UserController.login(..)) " +
            "|| execution(* com.example.videoplay.controller.UserController.register(..)) " +
            "|| execution(* com.example.videoplay.controller.UserController.updateUserInfo(..))")
    public void userLoginBefore(JoinPoint joinpoint) {
        HttpServletRequest request= (HttpServletRequest) joinpoint.getArgs()[0];
        String method=joinpoint.getSignature().getName();
        try{
            Map<String,String> map= (Map<String, String>) joinpoint.getArgs()[1];
            String ipaddress=map.get("ip")==null?request.getRemoteAddr():map.get("ip"); //ip地址
            insertLog(-1,map.toString(),method,ipaddress);
        }catch (Exception e) {
            System.out.println("user login failed");
        }

    }

    private void insertLog(int userId, String paramsMap, String method, String ip) {
        try {
            int res=logService.insertLog(userId,paramsMap,method,ip);
            if(res==0){
                System.out.println("insert log failed");
            }
        }catch (Exception e){
            System.out.println("insert log failed");
            e.printStackTrace();
        }
    }

}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇