SpringIoc

IoC(控制反转,Inverse of Control)是Spring容器的内核

BeanFactory和ApplicationContxt
Bean工厂是Spring框架最核心的接口。应用上下文ApplicationContext建立在BeanFactory基础之上
XmlBeanFactory通过Resource装载Spring配置信息并启动容器,然后通过getBean从容器中获取对象
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource res = resolver.getResource("classpath:com/smart/beanfactory/beans.xml");
BeanFactory bf = new XmlBeanFactory(res);


如果BeanFactory是Spring的心脏,那么SpplicationContext就是完整的身躯
ApplicationContext ctx = new ClassPathXmlApplicationContext("com/smart/context/beans.xml");
如果放在文件系统路径下:
ApplicationContext ctx = new FileSystemXmlApplicationContext("com/smart/context/beans.xml");

Spring3.0支持基于类注解的配置方式,主要功能来自JavaConfig的子项目。标注@Configuration注解的pojo即可提供Spring所需的Bean配置信息
@Configuration
public class Beans {

@Bean(name = "car")
public Car buildCar(){
Car car = new Car();
car.setName("红旗");
return car;
}
}
public class AnnotationApplicationContext {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class);
Car car = ctx.getBean("car", Car.class);
}
}
WebApplicationContext类体系结构
webApplicationContext是专门为Web应用准备的。允许从相对Web根目录的路径中装载配置文件,完成初始化工作。WebApplicationContext可以获得ServletContext的引用,整个Web应用上下文对象作为属性放置到ServletContext中。
初始化需要ServletContext实例,借助web.xml中配置自启动的Servlet或者Web容器监听器(ServletContextListener)可以完成。
用于启动WebApplicationContext的Servlet和Web容器监听器:
org.springframework.context.COntextLoaderServlet
org.springframework.web.context.ContextLoaderListener

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/viewspace-dao.xml, /WEB-INF/viewspace-service.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
ContextLoaderListener通过web容器上下文参数contextConfigLocation获取Spring配置文件的位置。指定多个用逗号、空格或分号分隔均可。默认路径是相对于web的部署根路径
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/viewspace-dao.xml, /WEB-INF/viewspace-service.xml</param-value>
</context-param>
<servlet>
<servlet-name>springContextLoaderServlet</servlet-name>
<servlet-class>org.springframework.context.COntextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
WebApplicationContext需要日志功能,用户可以将Log4J配置文件放置到类路径WEB-INF/classes下,此时Log4J引擎即可顺利启动。如果Log4J配置文件放置在其他位置,还比须在web.xml中指定Log4J的配置文件位置。Spring为Log4J引擎提供了两个类似于启用WebApplicationContext的实现类:Log4JConfigServlet和Log4JConfigListener,不管采用哪种方式都必须能保证在装在Spring的配置文件之前先装载Log4J配置信息
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/viewspace-dao.xml, /WEB-INF/viewspace-service.xml</param-value>
</context-param>
<!-- 指定Log4J的配置文件位置 -->
<context-param>
<param-name>Log4JConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>

<!-- 装载Log4J配置文件的自启动Servlet -->
<servlet>
<servlet-name>log4JConfigServlet</servlet-name>
<servlet-class>org.springframework.web.util.Log4JConfigServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>springContextLoaderServlet</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
使用监听器的话,必须将Log4JConfigListener放置在ContextLoaderListener的前面。采用以上的配置方式,Spring将自动使用XmlWebApplicationContext启动Spring容器,即通过XML文件为Spring容器提供Bean的配置信息。

如果使用@Configuration的Java类提供配置信息,则web.xml的配置需要如下配置:
<web-app>
<!-- 通过指定context参数,让Spring使用AnnotationConfigWebApplicationContext而非XmlWebApplicationContext启动容器 -->
<context-param>
<param-name>contextClass</param-name>
<param-valud>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>

<!-- 指定标注了@Configuration的配置类,多个可以使用逗号或空格分隔 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.smart.AppConfig1</param-value>
</context-param>

<!-- ContextLoaderListener监听器将根据上面配置使用AnnotationConfigWebApplicationContext根据contextConfigLocation指定的配置类启动Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

资源加载:
为了访问不同类型的资源,需要使用响应的Resource实现类,这样比较麻烦。Spring提供了一个强大的加载资源的机制,不仅能够通过"classpath:"、"file:"等资源地址前缀识别不同的资源类型,还支持Ant风格带通配符的资源地址。
资源地址前缀 对应资源类型
classpath: 从类路径中加载资源,classpath:和classpath:/是等价的,都是相对于类的跟路径。资源文件可以在标准的文件系统中,也可以在.jar或者.zip的类包中
file: 使用URLResource从文件系统目录中装载资源,可采用绝对或相对路径
http:// 使用URLResource从web服务器中装载资源
ftp:// 使用URLResource从FTP服务器中装载资源
没有前缀: 根据ApplicationContext具体实现类采用类型的Resource
其中和"classpath:"对应的还有“classpath*:”前缀。假设有多个jar包或者文件系统类路径下都有一个相同的包名,“classpath:”只会在第一个加载的com.smart包下查找,而"classpath*:"会扫描所有这些JAR包及类路径下出现的com.smart类路径。
Ant风格资源地址支持三种通配符:
?:匹配文件名中的一个字符
*:匹配文件命中的任意个字符
**:匹配多层路径

Bean装配:
要是应用程序中的Spring容器成功启动,需要同时满足以下3方面的条件
Spring框架的类包都已经放到应用程序的类路径下
应用程序为Spring提供完备的Bean配置信息

bean命名:
id满足xml对id的规范
name属性进行命名属性上没有字符上的限制
spring不允许出现两个相同id的bean,但却可以出现两个相同name的bean,如果有多个name相同的bean,getBean(beanName)获取的是最后声明的bean
如果id和name都未指定,spring自动将全限定类名作为bean的名称
如果id和name都未指定,且有多个同类的bean的话,获取指定bean应该是getBean("com.smart.Car");getBean("com.smart.Car#1)分别获得第一个第二个。

依赖注入:
属性注入:
<bean id="car" class="com.smart.Car">
<property name="name">
<value>小汽车</value>
</property>
</bean>
一般情况下,java的属性变量名都以小写字母起头,如maxSpeed。但也存在特殊的情况,考虑到一些特定意义的大写英文缩略词,javaBean也允许大写字母起头的属性变量名,不过必须满足“变量的前两个字母要么全部大写,要么全部小写”的要求。
构造函数注入:
类型确定位置:
<bean id="car1" class="com.smart.ditype.Car">
<constructor-arg type="java.lang.String">
<value>红旗CA72</value>
</constructor-arg>
<constructor-arg type="double">
<value>2000</value>
</constructor-arg>
</bean>
索引确定位置:
<bean id="car2" class="com.smart.Car">
<constructor-arg index="0" value="红旗CA72"/>
<constructor-arg index="1" value="中国一汽">
</bean>
索引和类型也可以联合使用。
自身类型反射注入:
<bean id="boss" class="com.smart.Boss">
<constructor-arg>
<ref bean="car"/>
</constructor>
</bean>
注意不要出现循环依赖。

注入参数:
1、字面量
value标签方式注入
<bean id="car" class="com.smart.Car">
<property name="maxSpeed">
<value>200</value>
</property>
</bean>
2、引用其他bean:
<bean id="car" class="com.smart.Car"/>
<bean id="boss" class="com.smart.Boss">
<property name="car">
<ref bean="car"></ref>
</property>
</bean>
如果有两个配置文件,其中一个呗另一个加载。两个配置文件里面都有同样命名的bean。如何选择引用哪个呢?
<!-- 该Bean和父容器的Car Bean具有相同的id -->
<bean id="Car" class="com.smart.Car">
<property name="brand" value="吉利CT5"/>
</bean>
<bean id="boss" class="com.smart.Boss">
<property name="car">
<!-- 引用父容器中的car,而非这里定义的Bean。如果采用<ref bean="car">将引用本容器处的car -->
<ref parent="car"/>
</property>
</bean>
3、集合类型属性
List:
<bean id="boss1" class="com.smart.Boss">
<property name="factorites">
<list>
<value>看报</value>
<value>赛车</value>
</list>
</property>
</bean>
Map:
<bean id="boss1" class="com.smart.Boss">
<property name="jobs">
<map>
<entry>
<key><value>AM</value></key>
<value>会见客户</value>
</entry>
</map>
</property>
</bean>
如果某一Map元素的键和值都是对象,则可以采取以下的配置方式:
<entry>
<key><ref bean="keyBean"/></key>
<ref bean="valueBean"/>
</entry>
Properties:
<bean id="boss1" class="com.smart.Boss">
<props>
<prop key="jobMail">john-office@smart.com</prop>
</props>
</bean>
可以使用util命名空间配置集合类型的Bean。如:
<util:list id="favoriteList" list-class="java.util.LinkedList">
<value>看报</value>
<value>赛车</value>
</util:list>
简化配置方式,可以采用p这个命名空间。采用p命名空间之后,对于字面值属性,其格式改为:p:属性名="xxx",对于引用对象的属性,其格式为:p:属性名_ref="xxx"

自动装配:
bean元素提供了一个指定自动装配类型的属性:autowire="<自动装配类型>"
byName、byType、constructor、autodetect
bean的作用域
bean元素的scope标签指定作用域
singleton、prototype、requesr、session、globalSession

基于注解的配置:
注解定义bean
@Component
@Repository、@Service、@Controller这三个特殊类型注解是为了让注解类本身的用途清晰化

使用注解配置信息启用Spring容器
使用context命名空间,它提供了通过扫描类名以及应用注解定义Bean的方式
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">

<!-- 扫描包以应用注解定义的Bean -->
<context:component-scan base-package="com.smart"/>

</beans>

如果仅希望扫描特定的类而并非基包下所有的类,那么可以使用resource-pattern属性过滤出特有的类,如:
<context:component-scan base-package="com.smart" resource-pattern="anno/*.class"/>
这里将基类包设置为com.smart,默认情况下resource-pattern属性的值为**/*.class,即基类包里的所有类
通过resource-pattern属性仅可以按照自愿名称对基类包中的类进行过滤,但如果仅使用这个,会发现很多时候它并不能满足用户的要求,如仅过滤基类保重实现了XXXService接口的类或者标注了某个特定注解的类等。
不过这些需求可以很容易通过<context:component-scan-scan>的过滤子元素实现,例如:
<context:component-scan base-package="com.smart">
<context:include-filter type="regex" expression="com.smart.anno.*"/>
<context:exclude-filter type="aspecth" expression="com.smart..*Controller+"/>
</context:component>
<context:include-filter>表示要包含的目标类,<context:exclude-filter>表示要排除在外的目标类。这两个过滤元素支持多种类型的过滤表达式:
类型 示例 说明
annotation com.smart.XxxAnnotation 所有标注了XxxAnnotation的类。该类型目标类是否标注了某个注解进行过滤
assignable com.smart.XxxService 所有基层或扩展XxxService的类,盖雷星采用目标类型是否基层或扩展某个特定类名进行过滤
aspetj com.smart..*Service+ 所有类名以Service结束的类以及基层或扩展它们的类。该类型采用AspectJ表达式进行过滤
regex com.smart.anno..* 所有com.smart.anno类包下的类。该类型采用正则表达式根据目标类的类名进行过滤
custom com.smart.XxxTypeFilter 采用XxxTypeFile 通过代码的方式根据过滤规则。该类必须实现org.springframework.core.type.TypeFilter接口

自动装配Bean
@AutoWired类型注入 required属性代表如果找不到是否抛异常
@Autowired(required=false)
private LogDao logDao;
@Qualifier 名称注入
@Qualifier("logDao")
private LogDao logDao;
对类成员变量及方法的入参进行标注
自动将LogDao传给方法入参
@Autowired
public void setLogDao(LogDao logDao){
this.logDao = logDao;
}
自动将名为userDao的Bean传给方法入参
@Autowired
@Qualifier("userDao")
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
如果一个方法拥有多个入参,在默认情况下,Spring自动选择匹配入参类型的Bean进行注入。Spring允许对方法入参标注@Qualifier以注入Bean的名称
@Autowired
public void init(@Qualifier("userDao")UserDao userDao, LogDao logDao){
this.userDao = userDao;
this.logDao = logDao;
}
对集合类型进行标注
如果对类中集合类的变量或方法入参进行@Autowired标注,那么Spring就会将容器中类型匹配的所有Bean都自动注入进来

@Autowired
private List<Plugin> plugins;

基于java类的配置
使用java类提供Bean定义信息-JavaConfig子项目
普通的POJO只要标注@Configuration注解,就可以为Spring容器提供Bean定义的信息。每个标注了@Bean的类方法都相当于提供一个Bean的定义信息
@Configuration
public class AopConf{
@Bean
public UserDao userDao(){
return new UserDao;
}
@Bean
public LogDao logDao(){
return new LogDao();
}

@Bean
public LogonService logonService(){
LogonService logonService = new LogonService();
//将前面定义的Bean注入到logonService的Bean中
logonService.setLogDao(logDao());
logonService.setUserDao(userDao());
return logonService;
}
}
@Configuration注解说明这个类可用于为Spring提供Bean的定义信息。类的方法出可以标注@Bean注解,Bean的类型由方法返回值类型决定,名称和方法名相同。也可通过入参显式指定Bean名称,如:@Bean(name="userDao")。直接在@Bean所标注的方法中提供Bean的实例化逻辑。
如果Bean在多个@Configuration配置类中定义,如何引用不同配置类中定义的Bean呢?
@Configuration
public class DaoConfig{
@Bean
public UserDao userDao(){
return new UserDao();
}
@Bean
public LogDao logDao(){
return new LogDao();
}
}
@Configuration注解类本身已经标注了@Component注解
@Configuration
public class ServiceConfig {
@Autowired
private DaoConfig daoConfig;

public LogonService logonService(){
LogonService logonService = new LogonService();

logonService.setLogDao(daoConfig.logDao());
logonService.setUserDao(daoConfig.userDao());
return logonService;
}
}
直接通过@Configuration类启动spring容器
Spring提供了一个AnnotationConfigApplicationContext类,能够直接通过标注@Configuration的java类启动Spring容器。
public class javaConfigTest {
public static void main(String[] args){
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConf.class);
LogonService logonService = ctx.getBean(LogonService.class);
logonService.printHello();
}
}
ApplicationConfigApplicationContext还支持通过编码的方式加载多个@Configuration配置类,然后通过刷新容器应用这些配置类。
public class javaConfigTest {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
//注册多个@Configuration配置类
ctx.register(DaoConfig.class);
ctx.register(ServiceConfig.class);
//刷新容器以应用这些注册的配置类
ctx.refresh();

LogonService logonServic = ctx.getBean(LogonService.class);
logonService.printHello();
}
用户可以通过代码逐个注册配置类,也可以通过@Import将多个配置类组装到一个配置类中,这样仅仅需要注册这个组装好的配置类就可以启动容器了。

@Configuration
@Import(DaoConfig.class)
public class ServiceConfig {
@Bean
public LogonService logonService(){
LogonService logonService = new LogonService();
return logonService;
}
}
通过xml配置文件引用@Configuration的配置
标注了@Configuration的配置类本身相当于一个标注了@Component的类,也是一个Bean,它可以被Spring的<context:component-scan>扫描到。因此,如果希望将配置类组装到XML配置文件中,通过XML配置文件启动Spring容器,仅需要在XML中通过<context:component-scan>扫描到对应的配置即可。
<context:component-scan base-package="com.smart.conf" resource-pattern="AppConf.class" />

通过Configuration配置类引用XML配置信息:
@Configuration配置类中可通过@ImportResource引入XML配置文件,在配置类中即可直接通过@Autowired引用XML配置文件中定义的Bean。

@Configuration
@ImportResource("classpath:com/smart/conf/beans2.xml")
public class LogonAppConfig {
@Bean
@Autowired //通过方法入参自动引入userDao和logDo
public LogonService logonService(UserDao userDao, LogDao logDo) {
LogonService logonServicve = new LogonService();
logonService.setUserDao(userDao);
logonService.setLogDao(logDao);
return logonServic;
}

}

不同配置方式的比较
bean定义:
基于xml:
在xml文件中通过<bean>元素定义Bean
基于注解:
在Bean实现了出通过标注@Component或衍型类(@Repository、@Service及@Controller)定义Bean
基于java类:
在标注了@Configuration的java类中,通过在此类方法上标注@Bean定义一个Bean。
bean名称:
基于xml:
通过bean的id或name属性,例如:<bean id="userDao" class="com.bbt.UserDao"/> 默认名称为com.bbt.UserDao#0
基于注解:
通过注解的value属性定义,如:@Component("userDao")。默认名称为小写字母大头的类名(不带包名)
基于java类:
通过@Bean的name属性定义,如@Bean("userDao"),默认名称为方法名
bean注入:
基于xml:
通过<property>资源素或通过p命名空间的动态属性进行注入
基于注解:
通过在成员变量或方法入参出标注@Autowired,按类型自动匹配注入,黑可以配合使用@Qualifier按名称匹配方式注入
基于java类:
比较灵活,可以在方法处通过@Autowired使方法入参绑定Bean,然后在方法中通过调用代码进行注入,还可以通过调用配置类的@Bean方法进行注入
bean生命周期:
基于xml:
通过<bean>的init-method和destory-method属性指定Bean实现类的方法名。最多只能指定一个初始化方法和一个销毁方法
基于注解:
通过在目标方法上标注@PostConstruct和@PreDestory注解指定初始化或销毁方法,可以定义任意多个方法
基于java类:
通过@Bean的initMethod或destoryMethod指定一个初始化或销毁方法。对于初始化方法来说,可以直接在方法内部通过代码方式灵活定义初始化逻辑。
bean作用范围:
基于xml:
通过<bean>的scope属性指定
基于注解:
通过在类中标注@Scope指定
基于java类:
通过在Bean方法定义处标注@Scope指定
bean延迟初始化:
基于xml:
通过<bean>的lazy-init属性指定,默认为default,继承与<beans>的default-lazy-init设置,该值默认为false
基于注解:
通过在类定义出标注@Lazy指定,如@Lazy(true)
基于java类:
通过在Bean方法定义处标注@Lazy指定,如@Lazy指定

Bean不同配置方式的适用场合
基于xml配置
Bean实现类来源于第三方类库
命名空间的配置只能采用基于xml的配置
基于注解配置
Bean的实现类是当前项目开发的,可以直接在java类中适用基于注解的配置
基于java类配置
基于java类配置的优势在于可以通过代码方法控制Bean初始化的整体逻辑,所以如果实例化Bean的逻辑比较复杂,则比较适合用基于java类的配置方式
一般采用XML配置DataSource、SessionFactory等资源Bean,在xml中利用aop、context命名空间进行相关主题的配置。其他所有项目中开发的Bean都通过基于注解配置的方式进行配置。

原文地址:https://www.cnblogs.com/aigeileshei/p/7894753.html