转自:https://www.cnblogs.com/digdeep/p/4518571.html
作用域部分来自:https://www.cnblogs.com/qq78292959/p/3716827.html
https://blog.youkuaiyun.com/canot/article/details/50697345
前言:
源码+实例:你、值得拥有
3. FactoryBean接口
实现了FactoryBean接口的bean是一类叫做factory的bean。其特点是,spring会在使用getBean()调用获得该bean时,会自动调用该bean的getObject()方法,所以返回的不是factory这个bean,而是这个bean.getOjbect()方法的返回值
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
典型的例子有spring与mybatis的结合:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:config/mybatis-config-master.xml" />
<property name="mapperLocations" value="classpath*:config/mappers/master/**/*.xml" />
</bean>
我们看上面该bean,因为实现了FactoryBean接口,所以返回的不是 SqlSessionFactoryBean 的实例,而是她的 SqlSessionFactoryBean.getObject() 的返回值:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
private static final Log logger = LogFactory.getLog(SqlSessionFactoryBean.class);
private Resource configLocation;
private Resource[] mapperLocations;
private DataSource dataSource;
public SqlSessionFactory getObject() throws Exception {
if (this.sqlSessionFactory == null) {
afterPropertiesSet();
}
return this.sqlSessionFactory;
}
其实他是一个专门生产 sqlSessionFactory 的工厂,所以才叫 SqlSessionFactoryBean。 而SqlSessionFactory又是生产SqlSession的工厂。
还有spring与ibatis的结合:
<!-- Spring提供的iBatis的SqlMap配置 -->
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:sqlmap/sqlmap-config.xml" />
<property name="dataSource" ref="dataSource" />
</bean>
SqlMapClientFactoryBean 返回的是 getObject() 中返回的 sqlMapClient, 而不是 SqlMapClientFactoryBean 自己的实例
public class SqlMapClientFactoryBean implements FactoryBean<SqlMapClient>, InitializingBean {
private Resource[] configLocations;
private Resource[] mappingLocations;
private Properties sqlMapClientProperties;
private DataSource dataSource;
private boolean useTransactionAwareDataSource = true;
private Class transactionConfigClass = ExternalTransactionConfig.class;
private Properties transactionConfigProperties;
private LobHandler lobHandler;
private SqlMapClient sqlMapClient;
public SqlMapClient getObject() {
return this.sqlMapClient;
}
4. 依赖注入(DI)
1) 依赖注入的方式分为构造函数注入和setter方法注入:
构造函数注入:
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
//对于非简单参数,需要使用ref
<constructor-arg index="1" ref="bar"/>
</bean>
<bean id="bar" class="x.y.Bar"/>
setter方法注入:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:config/mybatis-config.xml" />
<property name="mapperLocations" value="classpath*:config/mappers/**/*.xml" />
</bean>
2)集合等复杂类型的注入:
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
也很简单,list属性就是 <list>里面包含<value>或者<ref>或者<bean>, set也类似。map是<map>里面包含<entry>这个也好理解,因为map的实现就是使用内部类Entry来存储key和value. Properties是 <props>里面包含<prop>.
5. <bean> 元素可以配置的属性:
<bean> 除了 id 和 class 属性之外,还有一些可选的属性:
1) scope属性
默认<bean> 的 scope就是 singleton="true", springmvc和struts2的重要区别之一就是spring的controll是单例的,而struts2的action是:scope="prototype" ,还有 scope="request" , scope="session",scope="globalSession"(仅用于portlet)
1.singleton:ioc容器只有一个共享bean实例(存储在单例缓存中),对该bean的后继请求和引用都返回被缓存的对象实例;设计模式里的单例:一个classloader中只有一个class存在,不一样滴;
让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用
<bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>
或者
<bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>
struts2的Action不是线程安全的,要求在多线程环境下必须是一个线程对应一个独立的实例,不能使用 singleton。
只要是带数据成员变量的类,为了防止多个线程混用数据,就不能使用singleton。对于我们用到的Service、Dao,之所以用了singleton,就是因为他们没有用到数据成员变量,如果谁的 Service需要数据成员变量,请设置singleton=false。
有状态的bean都使用Prototype作用域,而对无状态的bean则应该使用singleton作用域。
2. prototype:每一次请求(将其注入到另一个bean中或程序调用容器getBean)都产生一个新的bean实例,相当与一个new操作;
作用域:spring容器在初始化 配置 装饰 或装配完一个prototype实例后,将其交给客户端管理便不再过问;
不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。
3. request针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例:
request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置:
如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可:
<web-app>
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现:
<web-app>
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
接着既可以配置bean的作用域了:
<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>
4、session每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例:
和request配置实例的前提一样,配置好web启动文件就可以如下配置:
<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>
5、global session
类似于标准的HTTP Session作用域,仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。
配置实例:
和request配置实例的前提一样,配置好web启动文件就可以如下配置:
<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>
6、自定义:在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和prototype),spring的作用域由接口org.springframework.beans.factory.con**.Scope来定义,自定义自己的作用域只要实现该接口即可
2)abstract属性,是否是抽象的bean:
<bean id="baseDAO" abstract="true">
<property name="dataSource" ref="dataSource" />
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>
<bean id="collectionDAO" class="net.minisns.dal.dao.CollectionDAOImpl" parent="baseDAO" />
<bean id="commentDAO" class="net.minisns.dal.dao.CommentDAOImpl" parent="baseDAO" />
3)depends-on 依赖于某个bean,其必须先初始化:<bean id="xxx" class="xxx" depends-on="refbean" />
4)lazy-init="true" 是否延迟初始化,默认为 false
5) dependency-check 是否对bean依赖的其它bean进行检查,默认值为 none,可取值有:none, simple, object, all等
6)factory-method 和 factory-bean用于静态工厂和非静态工厂:
<bean id="bar" class="...StaticBarInterfaceFactory" factory-method="getInstance"/>
<bean id="barFactory" class="...NonStaticBarInterfaceFactory"/>
<bean id="bar" factory-bean="barFactory" factory-method="getInstance"/>
7)init-method, destory-method 指定bean初始化和死亡时调用的方法,常用于 dataSource的连接池的配置
8) lookup-method 方法注入:
<bean id="newsBean" class="..xxx" singleton="false">
<bean id="mockPersister" class="..impl.MockNewsPersister">
<lookup-method name="getNewsBean" bean="newsBean"/>
</bean>
表示 mockPersister 有一个依赖属性 newsBean,该属性的每次注入都是通过调用newsBean.getNewsBean() 方法获得的。
9) autowire 是否启用自动装配依赖,默认为 no, 其它取值还有:byName, byType, constructor
转自:https://www.cnblogs.com/digdeep/p/4518571.html