AOPIOC?还傻傻分不清?

120 阅读5分钟

AOP?IOC?还傻傻分不清?

我将会从以下几个角度来开展开对 IOC & AOP 的解释:

  • 什么是ioc
  • ioc的优点
  • 什么是aop
  • aop 优点

什么是ioc

控制反转(Inversion of Control,IoC)是一种设计模式,它反转了传统的程序控制流程,将控制权交给了框架或容器。

这里我举个例子:类 A 依赖于类 B

  • 传统方法是往往是类 A 中手动通过 new 关键字来 new 一个 B 的对象出来

public ClassA() { this.classBInstance = new ClassB(); }

  • ioc 模式从ioc容器中直接获取就行了

以本人的理解在传统的程序设计中,程序员编写的代码通常控制应用程序的流程,但在 IoC 中,控制权被转移给了外部框架或容器,这也是为什么叫做控制反转(对创建对象的控制权由程序员转向了第三方IoC 容器)

ioc的好处

正如上面所说将创建对象的控制权转交给第三方容,那有什么好处呢

  1. 降低代码复杂度: IoC 简化了组件之间的连接和协调,减少了手动管理依赖关系的复杂性,使得代码更加清晰和简洁
  2. 可扩展性: 在 IoC 中,添加新的组件或修改现有组件的逻辑不会影响到其他组件。这样,应用程序可以更容易地适应变化和扩展。
  3. 松散耦合(Loose Coupling): IoC 通过将组件之间的依赖关系外移,使得组件更加独立,降低了它们之间的耦合度。这使得代码更加灵活、易于理解和维护。
  4. 可维护性(Maintainability): 由于组件之间的关系由容器进行管理,因此在修改或添加新的组件时,不需要修改其他组件的代码。这简化了维护过程,减少了代码的修改范围。

IoC的主要实现方式有两种:依赖查找、依赖注入

那么依赖查找和依赖注入有什么区别呢? 依赖查找(Dependency Lookup)和依赖注入(Dependency Injection)都是软件设计中用于管理组件之间依赖关系的方式,它们的主要区别在于谁来管理依赖关系的实例化和传递

依赖查找:在依赖查找中,组件主动去查找(或请求)所需的依赖项。这通常通过在需要依赖项的组件内部调用容器或者工厂方法来实现。组件自己负责知道如何获取依赖项,并且有显式的依赖查找代码。

代码示例

interface Dependency {
    void doSomething();
}

// 依赖项的具体实现
class ConcreteDependency implements Dependency {
    @Override
    public void doSomething() {
        System.out.println("Doing something in ConcreteDependency");
    }
}

// 依赖查找示例
class DependentComponent {
    private Dependency dependency;

    public DependentComponent() {
        // 在构造函数中通过依赖查找获取依赖项
        dependency = DependencyContainer.getDependency();
    }

    public void useDependency() {
        dependency.doSomething();
    }
}

// 依赖容器,负责提供依赖项
class DependencyContainer {
    public static Dependency getDependency() {
        return new ConcreteDependency();
    }
}

public class Main {
    public static void main(String[] args) {
        DependentComponent dependentComponent = new DependentComponent();
        dependentComponent.useDependency();
    }
}

依赖注入:在依赖注入中,依赖项由外部实体(通常是容器或者框架)注入到组件中。组件不直接获取依赖项,而是通过构造函数、属性或者方法参数来接收依赖项。这样的设计使得组件更加独立,更容易测试和重用,因为它们不需要了解如何创建或者获取依赖项的细节。

interface Dependency {
    void doSomething();
}

// 依赖项的具体实现
class ConcreteDependency implements Dependency {
    @Override
    public void doSomething() {
        System.out.println("Doing something in ConcreteDependency");
    }
}

// 依赖注入示例
class DependentComponent {
    private Dependency dependency;

    // 通过构造函数进行依赖注入
    public DependentComponent(Dependency dependency) {
        this.dependency = dependency;
    }

    public void useDependency() {
        dependency.doSomething();
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建依赖项实例
        Dependency dependency = new ConcreteDependency();
        
        // 将依赖项注入到组件中
        DependentComponent dependentComponent = new DependentComponent(dependency);
        
        dependentComponent.useDependency();
    }
}

什么是aop

aop(Aspect-Oriented Programming 面向切面编程)是一种软件设计思想和编程范式,它旨在模块化横切关注点(cross-cutting concerns),如日志、事务管理、安全性等,使得这些关注点的代码可以更容易地重用和维护,同时减少了代码的重复性

我们来看一个案例 假设我们有一个简单的应用,其中包含一个服务类 UserService,它有一个方法 getUser 用于获取用户信息。我们希望在调用该方法时记录日志。

public interface UserService {
    String getUser();
}

// 用户服务实现类
public class UserServiceImpl implements UserService {
    @Override
    public String getUser() {
        return "User information";
    }
}

接下来,我们创建一个切面类 LoggingAspect,用于记录日志:


@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.UserService.getUser())")
    public void logBeforeGetUser() {
        System.out.println("Logging: Before getUser() method");
    }
}

在上面的代码中,我们定义了一个切面 LoggingAspect,并在其中使用 @Before 注解来定义一个前置通知,在调用 getUser() 方法之前打印日志。


@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }

    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
}

当我们运行这个主程序时,将会看到在调用 getUser() 方法之前打印出日志信息,这是通过AOP实现的。 AOP(Aspect-Oriented Programming,面向切面编程)的名字包含了两个关键词来描述其特点。

:指的是横切逻辑,原有业务逻辑代码不动,只能操作横切逻辑代码,所以面向横切逻辑。也就是说,AOP 允许开发者通过切面将与核心业务逻辑无关的横切关注点(例如日志记录、性能统计、事务管理等)与核心业务逻辑分离开来,使得业务逻辑更加清晰、可维护。

:横切逻辑代码往往要影响的是很多个方法,每个方法如同一个点,多个点构成一个面。这里有一个面的概念。AOP 的切面可以横切到多个模块或方法中,因此形成了一个“面”,即横切逻辑被应用的范围。通过定义切面,可以将横切关注点应用于多个组件或模块,从而实现了代码的模块化和重用。

综上所述,AOP 是一种通过切面将横切逻辑与核心业务逻辑分离开来,并且可以面向多个方法或模块的编程范式。