Spring解析

文章目录

IOC控制反转

  • 传统模式下,对象主动创建依赖。自己去new()对象。
  • IOC 模式,容器管理依赖生命周期

什么是 IoC(控制反转)

IoC 是一种设计原则,核心思想是:把对象的创建与依赖管理的控制权,从对象本身反转给外部容器或框架。

IoC(Inversion of Control,控制反转)容器是依赖注入(DI)的实现框架,负责管理对象的创建、配置和生命周期。

三大核心作用:

  1. 对象创建,不再写 new,容器读取配置(注解/XML/代码)决定创建哪个实现类。
  2. 依赖组装,容器自动分析依赖关系,按正确顺序创建所有对象。
  3. 生命周期管理

依赖注入(DI)

依赖注入是 IoC 最常见的实现方式,容器负责把依赖"注入"到对象中。

三种注入方式:

构造器注入

java 复制代码
public class OrderService {
    private final UserRepository repo;

    public OrderService(UserRepository repo) { // 容器自动传入
        this.repo = repo;
    }
}

Setter 注入

java 复制代码
public void setRepo(UserRepository repo) { this.repo = repo; }

字段注入

java 复制代码
@Autowired
private UserRepository repo;

AOP

AOP是什么?

Aspect-Oriented Programming 面向切面编程。AOP采用的是横向切面的方式,注入与主业务流程无关的功能,例如事务管理和日志管理。

AOP核心概念

Aspect 切面 = Pointcut + Advice (在哪里做 + 做什么)

Pointcut 切入点 = 拦截哪些方法,连接点的集合

Advice 通知 = 在切面中(类)的某个连接点(方法)采取的动作。一般有几种不同的通知方式:1)around; 2)before; 3)after; 4)exception; 5)return(返回通知)

JoinPoint 连接点 = 方法执行的具体时机

Weaving 织入 = 把切面应用到目标对象的过程。可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring在运行时完成织入。

底层原理

Spring AOP本质上是动态代理。Spring AOP的实现方式是动态织入,通过动态代理技术在运行时动态将要增强的代码织入到目标类中;

  • JDK动态代理(目标类有接口时用,通过反射实现)
  • CGLIB代理(目标类没有接口时用,通过继承实现)

示例

1)实体类

java 复制代码
public class User {
    private int id;
    private String name;
    private String role;

    public User(int id, String name, String role) {
        this.id = id;
        this.name = name;
        this.role = role;
    }

    // getter setter
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public String getRole() {
        return role;
    }

    @Override
    public String toString() {
        return "User{id=" + id + ", name=" + name + ", role=" + role + "}";
    }
}

2)注解

java 复制代码
public @interface MyLog {
    String value() default "";
}
  1. service层

UserService

java 复制代码
public interface UserService {
    User findUser(int id);
}

UserServiceImpl

java 复制代码
@Service
public class UserServiceImpl implements UserService{
    @MyLog("查询用户")
    @Override
    public User findUser(int id) {
        System.out.println("  >>> [业务] 查询用户 id=" + id);
        return new User(id, "张三", "admin");
    }

    @MyLog("新增用户")
    @Override
    public void addUser(User user) {
        System.out.println("  >>> [业务] 新增用户: " + user);
    }

    @MyLog("删除用户")
    @Override
    public void deleteUser(int id) {
        System.out.println("  >>> [业务] 删除用户 id=" + id);
    }
}

4)切面类

java 复制代码
@Aspect
@Component
public class LogAspect {
    // 切点1:拦截service包下所有方法
    @Pointcut("execution(* AOP.service.*.*(..))")
    public void serviceMethod() {}

    // 切点2:拦截有@MyLog注解的方法
    @Pointcut("@annotation(AOP.annotation.MyLog)")
    public void myLogMethod() {}
    // 5. 环绕通知 + 读取@MyLog注解内容
    @Around("myLogMethod()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        // 获取注解上的描述
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        MyLog myLog = method.getAnnotation(MyLog.class);
        String operation = myLog.value();

        long startTime = System.currentTimeMillis();
        System.out.println("【Around-前】操作: 【" + operation + "】开始执行");

        Object result;
        try {
            result = pjp.proceed(); // 执行真实方法
        } catch (Throwable e) {
            System.out.println("【Around-异常】操作: 【" + operation + "】发生异常");
            throw e; // 继续抛出,让AfterThrowing也能捕获
        }

        long endTime = System.currentTimeMillis();
        System.out.println("【Around-后】操作: 【" + operation
                + "】执行成功,耗时: " + (endTime - startTime) + "ms");
        return result;
    }


}

5)测试

java 复制代码
public class App {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx =
                SpringApplication.run(App.class, args);

        UserService userService = ctx.getBean(UserService.class);

        System.out.println("\n========== 测试1: 查询用户 ==========");
        userService.findUser(1);
        ctx.close();
    }
}
java 复制代码
========== 测试1: 查询用户 ==========
【Around-前】操作: 【查询用户】开始执行
  >>> [业务] 查询用户 id=1
【Around-后】操作: 【查询用户】执行成功,耗时: 1ms
相关推荐
daidaidaiyu4 小时前
ThingsBoard 规则链系统源码分析和自定义定时器
java
蝎子莱莱爱打怪5 小时前
🚀 🚀🚀2026年5月GitHub月榜精选:17个项目中挑出10个推荐,实操4个!
人工智能·后端·ai编程
小毛驴8505 小时前
spring-boot-maven-plugin,maven-compiler-plugin 功能对比
java·python·maven
csdn_aspnet5 小时前
Java 霍尔分区算法(Hoare‘s Partition Algorithm)
java·开发语言·算法
霸道流氓气质5 小时前
通义灵码 IDEA 插件完全使用指南
java·ide·intellij-idea
诸葛务农5 小时前
道路行驶条件下电动汽车永磁电机的有效使用寿命及永磁体的失效和回收再利用(下)
java·开发语言·算法
Percep_gan6 小时前
Java8中的stream的测试使用
java
砍材农夫6 小时前
物联网实战:Spring Boot MQTT | MQTT 设备模拟器演示(附源码)
java·spring boot·后端·物联网·spring·netty
我叫黑大帅6 小时前
解决聊天页内部滚轮改为页面滚动问题
javascript·后端·面试
EAIReport6 小时前
Spring AI 详解:Java 开发者快速落地 AI 应用
java·人工智能·spring