本质:Spring框架为POJO提供的各种服务共同组成了Spring的生命之树
Paste_Image.png
spring框架为基础,有很多家庭成员, 比如(Spring Web Flow, Spring Web Services, Spring Security, Spring Batch等等), 这些家族成员全部以Apache Lisence Version 2.0协议发布,共同组成了Spring Projects组合, 因为Spring Projects组合是开源产品,需要社区推动和发展, 活跃的开发社区可以为我们带来快速的反馈和支持,但没有任何主体或个人可以保证我们所需要的反馈和支持能够及时有效地得到满足。鉴于这一点, SpringSource
(原来的Interface21,即Spring框架的“东家”)在Spring Projects组合的基础上,提供了Spring Portfolio 产品,SpringSource为Spring Portfolio产品中的各成员提供咨询、培训和支持服务,Spring Portfolio只是SpringSource产品组合之一
Paste_Image.png Paste_Image.pngIoC的理念就是,让别人为你服务, 也就是让IoC Service Provider来为你服务, 其实IoC就这么简单!原来是需要什么东西自己去拿,现在是需要什么东西就让别人送过来
依赖注入的三种方式:
- 首先声明人和箭的接口
Person
package spring.read.note.ioc;
/**
* 人接口
* @author lxf
*/
public interface Person {
public void hunt();
}
Arrow
/**
* 弓箭接口
* @author lxf
*/
public interface Arrow {
public String getArrow();
}
- 构造方法注入, 被注入对象在其构造方法中声明依赖对象的参数列表
(1)在PersonImpl实现类中配置构造方法
public class PersonImpl implements Person {
private Arrow arrow;
public PersonImpl() {}
public PersonImpl(Arrow arrow) {
this.arrow = arrow;
}
@Override
public void hunt() {
System.out.println("I get " + arrow.getArrow() + " to hunt.");
}
}
(2)配置spring配置文件
<bean id="ArrowImpl" class="iocdi.ArrowImpl"/>
<bean id="PersonImpl" class="iocdi.PersonImpl">
<!-- 构造注入 -->
<constructor-arg ref="ArrowImpl"/>
</bean>
- setter方法注入, 被注入对象类中设置setter和getter方法
1.配置PersonImpl人的实现类
package spring.read.note.ioc;
/**
* 人实现类
* @author lxf
*/
public class PersonImpl implements Person{
private Arrow arrow;
@Override
public void hunt() {
System.out.println("I get " + arrow.getArrow() + " to hunt!");
}
//set注入一支箭
public void setArrow(Arrow arrow)
{
this.arrow = arrow;
}
}
2.配置spring配置文件
<bean id="arrowImpl" class="spring.read.note.ioc.ArrowImpl"></bean>
<bean id="personImpl" class="spring.read.note.ioc.PersonImpl">
<!-- setter注入 -->
<property name="arrow" ref="arrowImpl"/>
</bean>
- testMain测试
public class TestMain {
public static void main(String[] args) {
// 得到ApplicationContext对象
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-read-note.xml");
// 得到Bean
Person person = (Person)ctx.getBean("personImpl");
person.hunt();
}
}
输出:
I get an arrow to hunt.
- 接口注入, 不同于setter注入和构造注入,接口注入无需在xml文件里配置bean,而利用Java反射创建实现接口类的实例。
PersonImpl
public void hunt() {
Object obj = Class.forName("spring.read.note.ioc.ArrowImpl").newInstance();
arrow = (Arrow) obj;
System.out.println("I get " + arrow.getArrow() + " to hunt.");
}
testMain
Object obj = Class.forName("spring.read.note.ioc.PersonImpl").newInstance();
Person p = (Person) obj;
System.out.println("-----------------接口注入-----------------");
p.hunt();
推荐使用setter和构造方法注入
IoC Service Provider 的职责
- 业务对象的构建管理
- 业务对象间的依赖绑定
Spring的IoC容器之BeanFactory
Paste_Image.png- Spring提供了两种容器类型: BeanFactory 和 ApplicationContext 。
- BeanFactory: 延迟初始化策略, 客户端访问到对象的时候才初始化该对象以及依赖注入;
- ApplicationContext: 在 BeanFactory 的基础上构建,除了拥有BeanFactory 的所有支持,还提供事件发布、国际化信息支持等, 在该类型容器启动之后,默认全部初始化并绑定完成;
BeanFactory 的对象注册与依赖绑定方式
1.直接编码方式
Paste_Image.png Paste_Image.png
- BeanFactory 只是一个接口,我们最终需要一个该接口的实现来进行实际的Bean的管理, Default-ListableBeanFactory 就 是 这 么 一 个 比 较 通 用 的 BeanFactory 实 现 类 。
- DefaultListableBean-Factory 除了间接地实现了 BeanFactory 接口,还实现了 BeanDefinitionRegistry 接口,该接口才是在 BeanFactory 的实现中担当Bean注册管理的角色。基本上, BeanFactory 接口只定义如何访问容
器内管理的Bean的方法,各个 BeanFactory 的具体实现类负责具体Bean的注册以及管理工作。 -
BeanDefinitionRegistry 接口定义抽象了Bean的注册逻辑。通常情况下,具体的 BeanFactory 实现类会实现这个接口来管理Bean的注册
Paste_Image.png - 打个比方说, BeanDefinitionRegistry 就像图书馆的书架,所有的书是放在书架上的。虽然你还书或者借书都是跟图书馆(也就是 BeanFactory ,或许BookFactory可能更好些)打交道,但书架才是图书馆存放各类图书的地方。所以,书架相对于图书馆来说,就是它的“BookDefinitionRegistry”。
- 每一个受管的对象,在容器中都会有一个 BeanDefinition 的实例(instance)与之相对应,该BeanDefinition 的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象类、构造方法参数以及其他属性等。当客户端向 BeanFactory 请求相应对象的时候, BeanFactory 会
通 过 这 些 信 息 为 客 户 端 返 回 一 个 完 备 可 用 的 对 象 实 例 。 RootBeanDefinition 和 ChildBean-Definition 是 BeanDefinition 的两个主要实现类.
2.外部配置文件方式
- 配置文件的格式可以是Properties文件格式和XML文件格式
- 读取配置文件bean的注册和加载流程
BeanDefinitionReader 实现类将相应的配置文件内容读取并映射到 BeanDefinition, 将BeanDefinition注册到BeanDefinitionRegistry, - xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" ➥
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="djNewsProvider" class="..FXNewsProvider">
<constructor-arg index="0">
<ref bean="djNewsListener"/>
</constructor-arg>
<constructor-arg index="1">
<ref bean="djNewsPersister"/>
</constructor-arg>
</bean>
<bean id="djNewsListener" class="..impl.DowJonesNewsListener">
</bean>
<bean id="djNewsPersister" class="..impl.DowJonesNewsPersister">
</bean>
</beans>
- 读取xml配置文件完成注册和依赖绑定
public static void main(String[] args)
{
DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
BeanFactory container = (BeanFactory)bindViaXMLFile(beanRegistry);
FXNewsProvider newsProvider = ➥
(FXNewsProvider)container.getBean("djNewsProvider");
newsProvider.getAndPersistNews();
}
public static BeanFactory bindViaXMLFile(BeanDefinitionRegistry registry)
{
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
reader.loadBeanDefinitions("classpath:../news-config.xml");
return (BeanFactory)registry;
// 或者直接
//return new XmlBeanFactory(new ClassPathResource("../news-config.xml"));
}
3.注解方式
- 在Spring 2.5发布之前,Spring框架并没有正式支持基于注解方式的依赖注入
- Spring 2.5发布的基于注解的依赖注入方式,如果不使用classpath-scanning功能的话,仍然部分依赖于“基于XML配置文件”的依赖注入方式
- 注解是Java 5之后才引入的
@Component
public class FXNewsProvider
{
@Autowired
private IFXNewsListener newsListener;
@Autowired
private IFXNewsPersister newPersistener;
}
- @Autowired 它的存在将告知Spring容器需要为当前对象注入哪些依赖对象.
- @Component 则是配合Spring 2.5中新的classpath-scanning功能使用的\
- xml的classpath-scanning配置
<context:component-scan base-package="cn.spring21.project.base.package"/>
-
<context:component-scan/> 会到指定的包(package)下面扫描标注有 @Component 的类,如果找到,则将它们添加到容器进行管理,并根据它们所标注的 @Autowired 为这些类注入符合条件的依赖对象
-
main中加载并使用bean
public static void main(String[] args)
{
ApplicationContext ctx = new ClassPathXmlApplicationContext("配置文件路径");
FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("FXNewsProvider");
newsProvider.getAndPersistNews();
}
网友评论