Spring--IOC、DI和AOP的基本概念和实现步骤

基本概念

IOC:Inversion of Control —— 控制反转

IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。

DI:Dependency Injection —— 依赖注入

在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(依赖注入)来实现的。
比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。

AOP:Aspect Oriented Programming —— 面向切面编程

AOP(Aspect Oriented Programming)是一种编程范式,用于将横切关注点(cross-cutting concerns)从业务逻辑中分离出来。通过这种方式,可以将诸如日志记录、事务管理、安全检查等功能模块化,从而提高代码的可维护性和可重用性。

核心概念
切面(Aspect):一个关注点的模块化,如日志记录、事务管理等。
连接点(Join Point):程序执行过程中的某个特定点,如方法调用、异常抛出等。
通知(Advice):在特定的连接点上执行的动作,如前置通知、后置通知等。
切入点(Pointcut):匹配连接点的表达式,用于指定哪些连接点应该应用通知。
织入(Weaving):将切面代码插入到普通业务代码中的过程,可以在编译时或运行时完成。

IOC和DI的关系

IOC和DI的关系
IoC 是一种设计思想,强调的是控制权的转移,即从传统的在代码中直接操控对象转为由外部容器来管理对象及其生命周期。
DI 是实现IoC的一种方式,通过依赖注入机制,让对象在运行时自动获得所需的依赖,从而降低对象间的耦合度。

实现步骤

DI的实现步骤:

在Java中,Spring框架提供了多种实现依赖注入的方式,包括构造器注入、设值注入(setter injection)以及字段注入(field injection)。下面以Spring Boot项目为例,展示如何使用构造器注入来实现依赖注入。

1.定义Service层接口和实现
   public interface MyService {
       String provideInfo();
   }

   @Service
   public class MyServiceImpl implements MyService {
       @Override
       public String provideInfo() {
           return "Hello from Service";
       }
   }
2.构造器注入(Construtor injection)——(官方推荐)
   @Controller
   public class MyController {

       private final MyService myService;

       // 使用构造器注入MyService实例
       public MyController(MyService myService) {
           this.myService = myService;
       }

       @GetMapping("/info")
       public String getInfo() {
           return myService.provideInfo();
       }
   }
3. 字段注入(Field Injection)——(最简单的方式)
@Service
public class MyService {
    private String info;

    public String provideInfo() {
        return info;
    }
}

@Controller
public class MyController {

    // 使用字段注入MyService实例
    @Autowired
    private MyService myService;

    @GetMapping("/info")
    public String getInfo() {
        return myService.provideInfo();
    }
}
4. 设值注入(Setter Injection)
@Service
public class MyService {
    private String info;

    public String provideInfo() {
        return info;
    }

    // Setter方法用于注入依赖
    @Autowired
    public void setInfo(String info) {
        this.info = info;
    }
}

@Controller
public class MyController {

    private MyService myService;

    // 使用setter注入MyService实例
    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/info")
    public String getInfo() {
        return myService.provideInfo();
    }
}
5.三种依赖注入方式比较
注入方式可靠性可维护性可测试性灵活性循环关系的检测性能影响
Field不可靠很灵活不检测启动快
Constructor可靠不灵活自动检测启动慢
Setter不可靠很灵活不检测启动快

AOP的实现步骤

AOP的实现方式
  1. 前置通知(Before Advice)
    在方法执行前执行的通知。
  2. 后置通知(After Returning Advice)
    在方法成功返回后执行的通知。
  3. 异常通知(After Throwing Advice)
    在方法抛出异常后执行的通知。
  4. 最终通知(After (Finally) Advice)
    无论方法是否正常返回或抛出异常,都会执行的通知。
  5. 环绕通知(Around Advice)
    在方法执行前后都执行的通知,可以拦截方法调用。

示例代码
假设我们需要在所有方法调用前后添加日志记录功能,可以使用Spring AOP来实现。

1. 定义切面类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // 定义环绕通知
    @Around("execution(* com.example.demo.service.*.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("Method " + joinPoint.getSignature().getName() + " started");

        try {
            Object result = joinPoint.proceed();
            long end = System.currentTimeMillis();
            System.out.println("Method " + joinPoint.getSignature().getName() + " ended in " + (end - start) + "ms");
            return result;
        } catch (Throwable e) {
            System.out.println("Exception in method " + joinPoint.getSignature().getName() + ": " + e.getMessage());
            throw e;
        }
    }
}
2.定义目标类
import org.springframework.stereotype.Service;

@Service
public class MyService {

    public String provideInfo() {
        return "Hello from Service";
    }
}
3.定义控制器
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    private final MyService myService;

    public MyController(MyService myService) {
        this.myService = myService;
    }

    @GetMapping("/info")
    public String getInfo() {
        return myService.provideInfo();
    }
}
4.AOP 的优势
  • 模块化横切关注点:将日志记录、事务管理等通用功能模块化,提高代码的可维护性和可重用性。
    减少重复代码:避免在多个地方重复编写相同的代码。
    易于扩展:可以通过修改切面来轻松扩展功能,而无需修改业务逻辑代码。
5.总结
  • AOP 是一种强大的编程范式,用于将横切关注点从业务逻辑中分离出来。通过定义切面、连接点、通知和切入点等概念,可以将日志记录、事务管理等功能模块化,从而提高代码的可维护性和可重用性。Spring AOP 提供了一套完整的工具和API来实现这一目标。

关注我!带你学习更多的编程技巧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王路飞的挚友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值