IoC Introduction

Introduction to IoC

See IoC example on why to use IoC with an example in Pico. Changes to this example to use it with Spring are in Spring example.

Example for conventional lookup (e.g. with JNDI in EJBs):

public class Foo {
   public Foo() {
   }

public String service() { return BarManager.lookup("myBar").doSomething(); } }

Example of IoC 3:

public class Foo {
   private Bar bar;

public Foo(Bar bar) { this.bar = bar; }

public String service() { return bar.doSomething(); } }

Types

  • Method-based (M) IoC : Pass dependent components to the component with every method call
  • Interface-based (I) IoC (Type 1): Uses Interfaces like Serviceable, Configurable etc. for declaring dependencies
  • Setter-based (S) IoC (Type 2): Uses setters for setting dependent components
  • Constructor-based (C) IoC (Type 3): Uses constructors for declaring dependencies
Example Method based IoC :
public class Foo {
   public Foo() {  
   }

public String service(Bar bar) { return bar.doSomething(); } }

Example of IoC 1:

public class Foo implements Barable {
   public Foo() {  
   }

public void doBar(BarManager bm) { Bar bar = (Bar) bm.lookup("myBar"); bar.service(); } }

Example of IoC 2:

public class Foo {
   private Bar bar;

public Foo() { }

public void setBar(Bar bar) { this.bar=bar; }

public String service() { return bar.doSomething(); } }

Disadvantages

  • You declare your dependencies, some magic happens and they are resolved. Magic makes source code harder to understand than lookups (because they are implicit not explicit)

Advantages

  • If you use singletons or lookups your unit tests are difficult to write (Just see all those special J2EE unit frameworks). With lookups you usually have to implement a registry that supplies MockObjects. If your lookups are static methods replacing them with MockObjects is even more difficult. With lookups you might have to do this (if you can control the registry, which most of the time is impossible or at least hard to do):
// What if you can't change the created class
// in your singleton or registry? Do you need to rewrite
// the whole JNDI lookup classes?
BarManager.setBarClass("myBar", MockBar.class);

Foo foo = new Foo(); assertEquals("ping", foo.service());

IoC is more JUnit test friendly than lookups. With Type-3 IoC you just do:

Foo foo = new Foo(new MockBar());
assertEquals("ping", foo.service());

With Type-2 this would be:

Foo foo = new Foo();
foo.setBar(new MockBar());
assertEquals("ping", foo.service());
  • No external dependecies. You can develop and test your components in the enviroment you like, you do not need to use a special deployment enviroment for your components during development (like with JNDI / EJB)
  • Easier to reuse and easy exchangeable between different IoC containers. Either implement simple wrappers or add setters and interfaces to use components from e.g. Pico in Avalon and Spring

Advantages of Type-2

  • Beans are well understood by Java developers, beans exist in most projects
  • More easily satisfies optional dependencies

Disadvantages of Type-2

  • Dependencies can be seen from the code. What are dependencies and what are normal setters and getters? Additional setters and getters make code more noisy
  • Needs some XML (or other) meta data which makes understanding code more difficult from looking at it

Advantages of Type-3

  • Stronger contract between components
  • Components cannot exist in "limbo" state between creation and when they can be used. This is more defensive

Disadvantages of Type-3

  • You may need your constructors (I do not :-)
  • Inheritance can become more difficult.
03-13
### Spring框架中的IOC和AOP #### IOC:Inversion of Control —— 控制反转 控制反转是一种设计原则,描述了一种特定形式的对象依赖关系管理方法。在传统的编程模式下,对象 A 若要使用对象 B,则需自行创建或查找对象 B 的实例。这种方式导致了较高的耦合度。而在引入控制反转之后,这种依赖关系被颠倒过来。不再是由对象自己负责获取所需的资源和服务,而是由外部容器(如Spring容器)来提供这些依赖项给对象[^2]。 具体来说,在Spring环境中,开发者不需要手动编写代码去初始化Bean或者设置属性值,这一切都交给了Spring容器处理。这样做的好处是可以减少组件间的相互依赖程度,并简化应用程序的配置过程[^1]。 #### DI:Dependency Injection —— 依赖注入 依赖注入是实现控制反转的具体手段之一。它允许我们将一个类所需要的其他类作为参数传递进来而不是让这个类内部创建它们自己的实例。这不仅降低了模块间紧耦合的可能性,而且也方便测试因为可以在不同的环境下轻松替换掉实际的服务实现[^4]。 以下是几种常见的依赖注入方式: - **构造器注入**:这是官方推荐的做法,通过构造函数接收所需依赖并将其保存起来供后续调用。 - **字段注入**:虽然这种方法最为简便快捷,但由于缺乏显式的声明机制而被认为不够灵活也不利于单元测试。 - **设值注入**:即通过setter方法来进行赋值操作,适用于那些可能需要后期修改其状态的情况。 ```java // 构造器注入示例 public class ServiceImpl implements IService { private final Repository repository; @Autowired // 或者不加@Autowired,默认构造器自动装配 public ServiceImpl(Repository repository){ this.repository = repository; } } ``` #### AOP:Aspect Oriented Programming —— 面向切面编程 面向切面编程旨在解决横切关注点的问题,即将散布于多个位置的功能集中在一起形成独立的部分。比如日志记录、事务管理和安全性检查等功能往往会在系统的不同地方重复出现。借助AOP技术就可以把这些通用行为提取出来单独定义成所谓的“方面”,然后再指定哪些具体的执行路径应该应用该方面的逻辑[^3]。 为了更好地理解这一点,可以考虑这样一个场景:每当某个服务的方法被执行前后都需要打印一条消息表示开始结束时间戳。如果不用AOP的话就需要在每一个这样的地方加入相同的语句;但如果采用AOP则只需要在一个地方写出相应的拦截规则即可。 ##### AOP的关键术语解释如下: - 切入点(Pointcut): 表达式用于匹配连接点的位置。 - 连接点(Join Point): 应用程序运行过程中能够插入额外功能的地方。 - 增强Advice: 描述应当如何改变目标方法的行为。 - 引介(Introduction): 向现有类添加新方法或属性的能力。 - 织入(Weaving): 将增强织入到目标对象的过程,可以通过编译期、加载时或运行时期完成。 ```xml <!-- XML配置风格下的AOP例子 --> <aop:config> <aop:aspect id="loggingAspect" ref="logger"> <!-- 定义切入点表达式 --> <aop:pointcut expression="execution(* com.example.service.*.*(..))" id="serviceMethods"/> <!-- 在上述切入点前后的动作 --> <aop:before pointcut-ref="serviceMethods" method="logBefore"/> <aop:after-returning pointcut-ref="serviceMethods" method="logAfterReturning"/> </aop:aspect> </aop:config> <bean id="logger" class="com.example.LoggingAspect"/> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值