前回のブログでは、Springを用いたIoCの実装を示しました。ApplicationContext.xmlにはBeanの設定が含まれており、その中でBeanの基本的な使用法を紹介しました。今回はさらに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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="DaoImpl" class="Cuiyw.Spring.Dao.DaoImpl"></bean>
<bean id="ServiceImpl" class="Cuiyw.Spring.Service.ServiceImpl" scope="singleton">
<property name="dao" ref="DaoImpl"></property>
</bean>
</beans>
上記コードは以前のブログに記載されたものです。Beanの基本構造を確認できます。<beans>はSpring設定ファイルのルート要素であり、複数の<bean>要素を含むことができます。Beanでよく使われる属性はidとclassです。idは一意の識別子であり、他のBeanから参照する際に使用されます。classはどのクラスを指すかを指定します。また、scope属性も設定可能です。scopeには2種類があります: singleton(デフォルト)と non-singelton。singletonはSpringコンテナ内で一つのインスタンスのみが存在し、non-singeltonは毎回リクエストごとに新しいインスタンスが生成されます。
二、作成
Beanの命名メカニズム
idはSpringのコンテナ内でBeanオブジェクトを検索する際の最初の検索キーとなります。idがなければname属性を使用し、nameもなければクラス名がデフォルトとして使用されます。
Beanの別名: aliasタグを使用してBeanに別の名前を指定できます。
以下は前のXMLファイルを元にした設定です。ServiceImplというIDを持つBeanに別名を設定しています。このBeanはname、id、aliasいずれからでも取得できます。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="DaoImpl" class="Cuiyw.Spring.Dao.DaoImpl"></bean>
<bean id="ServiceImpl" class="Cuiyw.Spring.Service.ServiceImpl" scope="singleton" name="ServiceA">
<property name="dao" ref="DaoImpl"></property>
</bean>
<alias name="ServiceA" alias="ServiceA1"/>
</beans>
package Cuiyw.SpringAop;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import Cuiyw.Spring.IService.IService;
public class App
{
public static void main( String[] args )
{
ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"ApplicationContext.xml"});
BeanFactory factory=context;
IService service=(IService)factory.getBean("ServiceA1");
service.service("Cuiyw ServiceA1");
service=(IService)factory.getBean("ServiceA");
service.service("Cuiyw ServiceA");
service=(IService)factory.getBean("ServiceImpl");
service.service("Cuiyw ServiceImpl");
}
}
三、注入
- 基本型と文字列
value要素を使用して設定します。上のコードを少し変更します。
<property name="baseProperty" value="222"></property>
package Cuiyw.Spring.Service;
import Cuiyw.Spring.IDao.IDao;
import Cuiyw.Spring.IService.IService;
public class ServiceImpl implements IService{
private IDao dao;
private int baseProperty;
public IDao getDao() {
return dao;
}
public void setDao(IDao dao) {
this.dao = dao;
}
public void service(String name) {
System.out.println(dao.sayHello(name)+" baseProperty:"+getBaseProperty());
}
public int getBaseProperty() {
return baseProperty;
}
public void setBaseProperty(int baseProperty) {
this.baseProperty = baseProperty;
}
}
文字列タイプの場合、XMLパーサーは文字列としてデータを解析します。もし属性が文字列タイプでない場合は、PropertyEditorsによって他のタイプに変換されます。例えば時間タイプなど。
- Beanの注入
上記コードでBeanの注入が行われています。ServiceImplにDaoImplを注入しています。refを使用して設定します。
- 集合の注入
リスト、マップ、セット、プロパティなどの一般的な集合があります。以下のコードではServiceImplにいくつかの属性を定義し、コンテキストで属性を注入しています。テストのためにDaoImplにもsという属性を追加しています。
package Cuiyw.Spring.Dao;
import java.util.Calendar;
import Cuiyw.Spring.IDao.IDao;
public class DaoImpl implements IDao{
public String s;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public String sayHello(String name) {
int hour=Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
if(hour<6) return "凌晨早,"+name;
if(hour<12)return "早上好,"+name;
if(hour<13)return "中午好,"+name;
if(hour<18)return "下午好,"+name;
return "晚上好,"+name+", s="+s;
}
}
package Cuiyw.Spring.Service;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import Cuiyw.Spring.IDao.IDao;
import Cuiyw.Spring.IService.IService;
public class ServiceImpl implements IService{
private IDao dao;
private int baseProperty;
private List<Object> lists;
private Set<Object> sets;
private Map<Object, Object> maps;
private Properties pros;
public IDao getDao() {
return dao;
}
public void setDao(IDao dao) {
this.dao = dao;
}
public void service(String name) {
System.out.println(dao.sayHello(name)+",baseProperty:"+getBaseProperty());
for(int i=0;i<lists.size();i++)
{
Object obj=lists.get(i);
System.out.println(obj.getClass().getName());
}
for(Object obj : sets)
{
System.out.println(obj.getClass().getName());
}
//遍历maps中的key
for (Object key : maps.keySet()) {
System.out.println("Key = " + key);
}
//遍历maps中的值
for (Object value : maps.values()) {
System.out.println("Value = " + value);
}
Set<String> pro=pros.stringPropertyNames();
Iterator<String> it=pro.iterator();
while(it.hasNext()){
Object key=it.next();
System.out.println(key+"----"+pros.getProperty((String) key));
}
}
public int getBaseProperty() {
return baseProperty;
}
public void setBaseProperty(int baseProperty) {
this.baseProperty = baseProperty;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Set<Object> getSets() {
return sets;
}
public void setSets(Set<Object> sets) {
this.sets = sets;
}
public Map<Object, Object> getMaps() {
return maps;
}
public void setMaps(Map<Object, Object> maps) {
this.maps = maps;
}
public Properties getPros() {
return pros;
}
public void setPros(Properties pros) {
this.pros = pros;
}
}
主に注入の設定です。list、map、set属性には基礎タイプのvalue=1と2つのDaoImplタイプを設定しています。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="DaoImpl" class="Cuiyw.Spring.Dao.DaoImpl">
<property name="s" value="cyw"></property>
</bean>
<bean id="ServiceImpl" class="Cuiyw.Spring.Service.ServiceImpl" scope="singleton" name="ServiceA">
<property name="dao" ref="DaoImpl"></property>
<property name="baseProperty" value="222"></property>
<property name="lists">
<list>
<value>1</value>
<ref bean="DaoImpl" />
<bean class="Cuiyw.Spring.Dao.DaoImpl">
<property name="s" value="cuiywlists" />
</bean>
</list>
</property>
<property name="sets">
<set>
<value>1</value>
<ref bean="DaoImpl" />
<bean class="Cuiyw.Spring.Dao.DaoImpl">
<property name="s" value="cuiywsets" />
</bean>
</set>
</property>
<property name="maps">
<map>
<entry key="key1" value="1"></entry>
<entry key="key2" value-ref="DaoImpl"></entry>
<entry key="key3" >
<bean class="Cuiyw.Spring.Dao.DaoImpl">
<property name="s" value="cuiywmaps" />
</bean>
</entry>
</map>
</property>
<property name="pros">
<props>
<prop key="prokey1">prokeyA</prop>
<prop key="prokey2">prokeyB</prop>
</props>
</property>
</bean>
<alias name="ServiceA" alias="ServiceA1"/>
</beans>
mainメソッドを実行すると、すべての属性が正しく注入されていることがわかります。
- 自定义属性编辑器
一部の属性は直接注入できない場合があります。このようなケースでは、カスタムプロパティエディターを定義する必要があります。たとえば、日付タイプの例があります。
まず、PropertyEditorSupportを継承したクラスを定義し、setAsTextメソッドをオーバーライドします。
package Cuiyw.Spring.Service;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class CustomerProperty extends PropertyEditorSupport {
private String format="yyyy-MM-dd";
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
@Override
public void setAsText(String text) throws IllegalArgumentException {
// TODO Auto-generated method stub
SimpleDateFormat sdf=new SimpleDateFormat(format);
//super.setAsText(text);
try {
//转换对象,能过setValue方法重新赋值
this.setValue(sdf.parse(text));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
次に、設定ファイルにこのクラスを設定します。
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date" value="Cuiyw.Spring.Service.CustomerProperty"/>
</map>
</property>
</bean>
ここでServiceImplにjava.util.Date型のdate属性を追加し、設定ファイルで値を注入します。
<property name="date" value="2017-12-10"/>
四、注入方法
package Cuiyw.Spring.Service;
import Cuiyw.Spring.IDao.IDao;
public class IOCWay {
/*public IOCWay(IDao dao, String name) {
this.dao = dao;
this.name = name;
System.out.println("调用构造函数实例化参数");
}
*/
private IDao dao;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IDao getDao() {
return dao;
}
public void setDao(IDao dao) {
this.dao = dao;
}
public void print()
{
System.out.println(dao.sayHello(name));
}
}
上記はIOCWayクラスを作成し、コンストラクタは引数のインスタンス化をテストするために使用されています。
- プロパティ注入
上のコードではすべてプロパティ注入を使用しています。
<bean id="DaoImpl" class="Cuiyw.Spring.Dao.DaoImpl">
<property name="s" value="cyw"></property>
</bean>
- コンストラクタ注入
indexを使用してパラメータの位置を指定できます。
<bean id="IOCWay" class="Cuiyw.Spring.Service.IOCWay">
<constructor-arg type="java.lang.String" index="1">
<value>cuiyw</value>
</constructor-arg>
<constructor-arg ref="DaoImpl" index="0"></constructor-arg>
</bean>
- 静的ファクトリ方式
まず、ファクトリクラスを作成します。
package Cuiyw.Spring.Service;
import Cuiyw.Spring.Dao.DaoImpl;
public class IOCFactory {
public static final DaoImpl getStaticFactoryDaoImpl(){
return new DaoImpl("cuiyw");
}
}
Beanを設定するとき、以下のように設定します。daofactoryにfactory-methodを設定しています。
<bean id="IOCWay1" class="Cuiyw.Spring.Service.IOCWay">
<property name="dao" ref="daofactory"></property>
<property name="name" value="cyw"></property>
</bean>
<bean name="daofactory" class="Cuiyw.Spring.Service.IOCFactory" factory-method="getStaticFactoryDaoImpl"></bean>
- インスタンスファクトリ方式
ファクトリクラスにインスタンス化メソッドを追加します。
package Cuiyw.Spring.Service;
import Cuiyw.Spring.Dao.DaoImpl;
public class IOCFactory {
public static final DaoImpl getStaticFactoryDaoImpl(){
return new DaoImpl("cuiyw");
}
public final DaoImpl getInstanceFactoryDaoImpl(){
return new DaoImpl("cuiyw");
}
}
インスタンスファクトリ方式では、ファクトリクラスをインスタンス化する必要があります。そのため、設定時にfactory-beanを指定します。
<bean id="IOCWay2" class="Cuiyw.Spring.Service.IOCWay">
<property name="dao" ref="factorydao"></property>
<property name="name" value="cyw"></property>
</bean>
<bean name="daofactory" class="Cuiyw.Spring.Service.IOCFactory"></bean>
<bean name="factorydao" factory-bean="daofactory" factory-method="getInstanceFactoryDaoImpl"></bean>
これで一般的な4つの注入方法を学びました。他にもいくつかの方法があり、注解による注入もありますが、ここではXMLの注入に焦点を当てています。通常はプロパティとコンストラクタがよく使われます。