实际开发中,我们如果在对象 A 内部去创建、修改或者注销另一个对象 B,这会导致对象之间非常复杂的依赖关系,不利于代码的维护更新。
比如我们直接在上层类内调用了底层类的构造方法,一旦底层类的构造方法发生改变,就必须修改所有上层类的代码。
( Dependency Injection ) 我们用依赖注入的方式来降低耦合度。所谓依赖注入,就是把底层对象作为参数传入上层对象。避免底层类被修改后上层类代码也要随之改动。我们一般通过构造方法或者 setter 方法注入底层对象。
主要采用设值注入,性能更好更易读。但对于依赖关系无需变化的 Bean 采用构造注入。所有的依赖关系全部在构造器内设定。
优势:使用依赖注入后,即使底层类发生变化,上层类代码也不必改动,大大降低了代码的耦合度。
劣势:但这也导致了我们在初始化对象的过程中要书写复杂的代码。
( Inversion of Control ) 控制反转,将对象的管理权交给 IOC 容器。
Spring 框架内会定义一个 IOC 容器类,通过其来统一管理对象的生命周期:创建、资源存取、注销;并自动维护对象间的依赖关系。用户只需要配置 XML 文件或者添加注解标明类之间的映射关系,初始化过程中的代码将由 IOC 容器自动完成。
IOC 容器底层通过工厂模式和 Java 反射机制来实现:
在 Spring 框架中已经定义了 ApplicationContext 和 BeanFactory 作为 IOC 容器类。其中 ApplicationContext是 BeanFactory 的子类,提供了事件发布、国际化信息支持等其他高级特性。
我们可以通过 IOC 容器类的 setBean 方法创建 Bean ,也可以通过 getBean 方法把 Bean 实例化并使用。
public void testUser(){
// 加载配置文件,创建 IOC 容器对象
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
// IOC 容器根据 Bean 创建对象实例
Person newUser = (Person) context.getBean("person");
// 调用对象方法
System.out.print(newUser.toString());
}Copy to clipboardErrorCopied
Java Bean 就是程序中被管理的对象在 IOC 容器中的代理,记录了对象信息。
Bean 包含以下参数:Bean 名称(name) 、所代理的类(class) 、以及作用域(scope)。
Spring 对 Bean 方法进行了抽象和封装,开发者只需要进行配置和调用简单接口,具体实现都交付给 Spring 工厂来管理。
在调用 getBean 方法时,Spring 的工作流大致可分为以下两步:
获取 BeanName,对传入的 name 进行解析,转化为可以从 Map 中获取到 BeanDefinition 的 bean name。 合并 Bean 定义,对父类的定义进行合并和覆盖,如果父类还有父类,会进行递归合并,以获取完整的 Bean 定义信息。 实例化,使用构造或者工厂方法创建 Bean 实例。 属性填充,寻找并且注入依赖,依赖的 Bean 还会递归调用 getBean 方法获取。 初始化,调用自定义的初始化方法。 获取最终的 Bean,如果是 FactoryBean 需要调用 getObject 方法,如果需要类型转换调用 TypeConverter 进行转化。
三个类 A、B、C,然后 A 关联 B,B 关联 C,C 又关联 A,这就形成了一个循环依赖。如果是方法调用是不算循环依赖的,循环依赖必须要持有引用。
无法解决
Spring 框架只支持单例下的设值循环依赖。原型模式检测到循环依赖会直接抛出 BeanCurrentlyInCreationException 异常。
https://www.jianshu.com/p/9ea61d204559
为类添加 @Configuration
注解,表示该类为配置类。起到类似 XML 文件的作用,配置 IOC 容器用来管理 Bean。
为配置类添加 @ComponentScan
注解,启用组件扫描。配置类将根据注解向 IOC 容器添加 Bean,默认扫描本类中的 @Bean 方法。
可以指定需要扫描的包,这会扫描包内的所有组件。如 @ComponentScan(value="com.company.project")
。
@Component
注解表示该类型被注册为 Bean 。Bean 的名称默认为类名的首字母小写,作用域默认为单例模式。
@Component("car")
。@Component("prototype")
。在 Spring MVC 中,我们可以把 @Component
细化为:
@Controller
注解:表示展示层的 Bean@Service
注解:表示业务层的 Bean@Repository
注解:表示数据访问层的 Bean@Component
@Scope("prototype")
class Car implements Vehicle{
@AutoWired
private FrameWork frameWork;
}Copy to clipboardErrorCopied
@Bean
注解方法返回类型将被注册为 Bean。Bean 的名称默认为方法名,作用域默认为单例模式。
@Bean(name = "myFoo")
。@Autowired
注解表示自动装配。在使用对象时 Spring 将根据类型自动查找 Bean 去创建对象,无法找到 Bean 则抛出异常。
@Autowired(required=false)
。@Qualifier
注解来指定 Bean 的名称。@Autowired
@Qualifier("car")
private Vehicle vehicle;Copy to clipboardErrorCopied
@Resource
注解表示自动装配。默认按对象名称去查找 Bean,找不到再按类型去查找 Bean。
@Resource(name="car")
或者 @Resource(type=Car.class)
。@Resource(name="car")
private Vehicle vehicle;Copy to clipboardErrorCopied
@Autowired 是 Spring 的注解,@Resource 是 J2EE 的注解。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。