Spring Framework是一个运用框架,框架一样平常是半成品,我们在框架的根本上可以不用每个项目自己实现架构、根本举动步伐和常用功能性组件,而是可以专注业务逻辑。因此学习Spring Framework在架构和模式方面的构造和事理,对我们在架构和模块级别的理解帮助极大。Spring Framework(参考1)的宗旨是简化Java开拓,紧张的手段如下:
(1)在架构上解耦:通过DI(依赖注入)管理类型依赖,通过AOP分离关注点,减少重复代码。
(2)在设计上广泛采取DIP(依赖颠倒)和ISP(接口隔离)等原则和Facade(外不雅观)等模式:供应简化的调用接口并封装了浩瀚出色的第三方组件。
(3)在措辞层面上采取表明:通过配置文件和Annotation(参考.NET Attribute)简化运用配置。
2.Spring Framework的架构和模块:
Spring Framework本身的架构是范例的疏松分层,外层可以按需引用全部内层,内层不能引用外层。Spring的根本组件如下图所示:
从图中可以看出,开始的模块只有从core\beans\aop\context四个组件,后来添加了context-support【1.2】扩展模块、expression【3.0】扩展模块和beans-groovy【4.0】扩展模块。
Spring上述模块的根本上,内建和封装了浩瀚的实用的通用组件,紧张的组件如图所示:
从图中可以看出,spring-oxm、spring-jdbc和spring-web是浩瀚模块依赖的核心,spring-oxm供应了Object和XML的映射支持。
二、根本知识1.DIP:DIP(依赖颠倒原则)是DI(依赖注入)的核心(参考2)。
(1)高层模块不应该依赖于低层模块。两者都该当依赖于抽象。
(2)抽象不应该依赖于细节。细节该当依赖于抽象。
说人话便是:将对详细类的引用转换成对其接口的引用,详细类只引用接口(引用==依赖,接口==接口或抽象类)。事实上我们调用详细类的时候在头脑里也是只关心其供应的API而非实现,DIP则通过在设计和重构阶段在技能手段上担保理解耦。
2.DI:DI(依赖注入)让我们不必手写工厂代码来管理接口和实现类的映射、工具的创建和生命周期的管理。
(1)接口注入:必须实现特定的接口才可以,侵入性太强,现在已经无人关心和利用。
(2)布局函数注入:依赖表示在布局函数的参数上。
(3)属性注入:依赖表示在属性上。
由于在实现时,可以将类型注册为自己的兼容类型,这样依赖注入就可以直接替代new实例化工具,这样理解和利用依赖注入工具还不如不该用或手写工厂了。依赖注入工具在实现时肯定会实现成一个支持不同配置和不同生命周期的工具工厂,但纵然没有供应一套添加依赖颠倒原则限定的API,也不虞味着我们把它当成new的替代品。犹如映射工具虽然在实现时可以任意映射,但不是用来取代赋值的,而是用来处理领域实体和视图模型等有实际对应关系的工具之间的映射。
(1)依赖配置:依赖配置是依赖注入实现的根本。依赖注入工具都至少支持代码配置和文件配置。Java中可以通过Annotation(.NET中通过Attribute)简化配置。
(2)工具工厂:根据配置返回一个或多个工具。这是核心功能。
(3)生命周期管理:一样平常供应至少4种级别的支持:浸染域、单例、线程、HTTP要求范围。
大多数依赖注入工具在支持依赖颠倒原则的根本上,在技能手段上实现了更多的功能,如类型的兼容转换、对依赖命名、在配置时直接传入工具等。
三、Spring依赖注入的要点Bean在Spring中便是POJO(.NET的POCO)。
Spring依赖注入须要节制的核心是3个类型BeanDefinition、BeanFactory和ApplicationContext。
1.BeanFactory
BeanFactory是spring中依赖注入的核心接口,其设计紧张采取了ISP(接口隔离原则),通过多层次的接口继续即担保了单个接口的内聚又担保了全体体系的简洁。这里我们要关注的核心是DefaultListableBeanFactory。
如图所示,查看XmlBeanFactory代码,可以看到XmlBeanFactory只是通过XmlBeanDefinitionReader载入了BeanDefinition配置,XmlBeanDefinitionReader卖力将配置解析到BeanDefinition。DefaultListableBeanFactory是真正的实现类,个中定义了类型为Map<String, BeanDefinition>的beanDefinitionMap列表用于存储依赖配置。
2.BeanDefinition:
BeanDefinition定义了配置元数据,无论利用java code、xml、Annotation还是Groovy脚本办法,不同的配置办法通过不同的BeanDefinitionReader解析为BeanDefinition。
3.ApplicationContext
ApplicationContext的核心都是将工具工厂功能委托给BeanFactory的实现类DefaultListableBeanFactory。目前最常用的是基于表明的AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext。
四、Spring依赖注入快速上手
1.利用Java配置代替xml配置
Java配置的核心是@Configuration和@Bean。定义生命周期利用@Scope,须要引入其他配置文件时利用@Import。
(1)@Configuration:运用了@Configuration表明的POCO成为了配置类。相称于xml配置文件。
(2)@Bean:配置类中运用了@Bean表明的方法成为了配置项。相称于xml中的Bean节点。
package me.test.spring_ioc;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;public class App { public static void main(String[] args) { AnnotationConfigApplicationContext container = new AnnotationConfigApplicationContext(AppConfig.class); String message = container.getBean(IAppService.class).Test(); System.out.println(message); container.close(); }}@Configurationclass AppConfig { @Bean public IAppService IAppService() { return new AppService(new Repository<SimpleEntity>()); }}class SimpleEntity { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}interface IAppService { String Test();}interface IRepository<T> { String Test();}class AppService implements IAppService { private IRepository<SimpleEntity> _repo; public AppService(IRepository<SimpleEntity> repo) { _repo = repo; } @Override public String Test() { return this._repo.Test(); }}class Repository<T> implements IRepository<T> { @Override public String Test() { return this.getClass().getName(); }}
如果是Web运用程序,该当利用AnnotationConfigWebApplicationContext,在JSP中可通过WebApplicationContextUtils获取ApplicationContext工具。
<%@page import=\公众swp.IAppService\"大众%><%@page import=\"大众org.springframework.web.context.WebApplicationContext\公众%><%@page import=\"大众 org.springframework.web.context.support.WebApplicationContextUtils\"大众%><html><body> <% WebApplicationContext context = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); String message = context.getBean(IAppService.class).print(); out.print(message); %></body></html>
2.基于Annotation的自动装置
自动装置紧张利用@ComponentScan、@Component和@Autowired。
(1)@ComponentScan:浸染在配置类上,启用组件扫描。扫描并注册标注了@Component(@Controller\@Service\@Repository)的类型。@Configuration已经运用了@Component表明。
(2)@Autowired:按类型自动装置。@Autowired和利用@Inject(JSR-330)或@Resource(JSR-250)的效果是类似的。@Autowired和@Inject默认按类型注入,@Resource默认按名称注入。
package me.test.spring_ioc;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.AnnotationConfigApplicationContext;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;public class App { public static void main(String[] args) { AnnotationConfigApplicationContext container = new AnnotationConfigApplicationContext(AppConfig.class); String message = container.getBean(IAppService.class).Test(); System.out.println(message); container.close(); }}@Configuration@ComponentScanclass AppConfig { /@Bean public IAppService IAppService() { return new AppService(new Repository<SimpleEntity>()); }/}class SimpleEntity { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; }}interface IAppService { String Test();}interface IRepository<T> { String Test();}@Componentclass AppService implements IAppService { private IRepository<SimpleEntity> _repo; @Autowired public AppService(IRepository<SimpleEntity> repo) { _repo = repo; } @Override public String Test() { return this._repo.Test(); }}@Componentclass Repository<T> implements IRepository<T> { @Override public String Test() { return this.getClass().getName(); }}
小结:
你至少该当知道的:
(1)BeanFactory和BeanDefinition
(2)DefaultListableBeanFactory和ApplicationContext
(3)AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext
(4)@Configuraton和@Bean
Spring的依赖注入在配置上是基于工具而不是类型,最先支持的是xml而不是表明,到现在也没有比较方便的代码配置机制。虽然现在已经从xml过渡到了表明办法,但基于工具的根本仍旧是影响很多方面的缺陷。