Spring 中控制反转(IOC)和面向切面编程(AOP)

 

Spring 中的控制反转(IOC)与依赖注入(DI)

控制反转(IOC, Inversion of Control)
  • 核心思想
    将对象的创建、依赖管理和生命周期控制权从程序员转移给 Spring 容器,实现解耦和模块化。

  • 传统方式的问题
    手动通过 new 关键字创建对象,导致代码耦合度高,难以维护和扩展。
    示例:

    // 传统方式:直接依赖具体实现
    public class UserService {
        private UserRepository userRepository = new UserRepositoryImpl();
    }
  • IOC 的实现方式
    通过 IOC 容器(如 ApplicationContext)管理对象(Bean),提供两种配置方式:

    • XML 配置:早期方式,显式定义 Bean 及其依赖。

      <bean id="userRepository" class="com.example.UserRepositoryImpl"/>
      <bean id="userService" class="com.example.UserService">
          <property name="userRepository" ref="userRepository"/>
      </bean>
    • 注解驱动:现代主流方式,使用 @Component@Service 等注解自动扫描和装配。

      @Service
      public class UserService {
          @Autowired
          private UserRepository userRepository;
      }
  • 依赖注入(DI)
    • 构造器注入(推荐):通过构造函数传递依赖。

      @Service
      public class UserService {
          private final UserRepository userRepository;
      
          @Autowired
          public UserService(UserRepository userRepository) {
              this.userRepository = userRepository;
          }
      }
    • Setter 方法注入:通过 Setter 方法赋值。

      @Service
      public class UserService {
          private UserRepository userRepository;
      
          @Autowired
          public void setUserRepository(UserRepository userRepository) {
              this.userRepository = userRepository;
          }
      }
    • 字段注入:直接通过 @Autowired 注解字段(简单但不推荐,易导致循环依赖)。

  • IOC 容器的核心功能
    • Bean 生命周期管理:包括初始化(@PostConstruct)和销毁(@PreDestroy)。

    • 作用域控制:支持 singleton(默认单例)、prototype(每次请求新对象)等作用域。

    • 延迟加载:通过 @Lazy 延迟初始化 Bean。

面向切面编程(AOP)

AOP 的核心概念
  • 目标问题
    解决横切关注点(如日志、事务、安全)在多个模块中重复出现的问题,避免代码冗余和高耦合。

  • 核心术语

    术语说明
    切面(Aspect)封装横切逻辑的模块(如日志工具类),通过 @Aspect 注解定义。
    连接点(Join Point)程序执行过程中的某个点(如方法调用、异常抛出)。
    通知(Advice)切面在连接点执行的具体动作(如方法执行前后),分为 @Before@After 等。
    切点(Pointcut)通过表达式匹配需要拦截的连接点(如指定某个包下的所有方法)。
    织入(Weaving)将切面代码插入目标对象的过程,Spring AOP 通过动态代理实现。
Spring AOP 的实现
  • 动态代理机制

    • JDK 动态代理:基于接口,要求目标类必须实现接口。

    • CGLIB 代理:基于子类继承,可代理未实现接口的类(需引入 cglib 依赖)。

  • 通知类型

    通知类型执行时机示例
    @Before目标方法执行前权限校验、日志记录
    @AfterReturning目标方法成功返回后记录返回值
    @AfterThrowing目标方法抛出异常后异常监控、回滚事务
    @After目标方法执行后(无论成功或异常)清理资源
    @Around包围目标方法,可自定义执行流程性能统计、事务管理
  • 切点表达式(Pointcut Expression)
    使用 AspectJ 表达式语法 定义拦截范围,常见形式:

    @Pointcut("execution(* com.example.service.*.*(..))") // 拦截 service 包下所有方法
    public void serviceMethods() {}
AOP 的实际应用示例
  • 日志记录切面

    @Aspect
    @Component
    public class LoggingAspect {
        @Before("execution(* com.example.service.*.*(..))")
        public void logMethodCall(JoinPoint joinPoint) {
            String methodName = joinPoint.getSignature().getName();
            System.out.println("Method " + methodName + " is called.");
        }
    }
  • 事务管理切面

    @Aspect
    @Component
    public class TransactionAspect {
        @Around("@annotation(org.springframework.transaction.annotation.Transactional)")
        public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
            try {
                System.out.println("Starting transaction...");
                Object result = joinPoint.proceed();
                System.out.println("Committing transaction...");
                return result;
            } catch (Exception e) {
                System.out.println("Rolling back transaction...");
                throw e;
            }
        }
    }
Spring AOP 的局限性
  • 仅支持方法级别的拦截:无法拦截字段访问或构造器调用。

  • 仅作用于 Spring 管理的 Bean:非容器管理的对象无法被代理。

  • 性能开销:动态代理会引入轻微性能损耗,但对大多数应用影响可忽略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值