有的时候我们一些类中的参数有一部分是重复的,如果不管这些重复的参数的话,会导致配置文件比较臃肿,尤其是当这些参数比较多而且被很多的bean用到的时候。那么最好的方式是这样的,将这些重复的东西抽取出来放在一个公共的模块中,那么我需要的时候,直接引用就可以了,就如同java中类的继承,可以将相同的部分放在一个公共的模块里即可。
抽象Bean
下面看一个实例:
package com.siti.spring20160305;
public interface Person {
void printName();
}
WangYang这个类实现了Person这个接口
package com.siti.spring20160305;
public class WangYang implements Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void printName() {
System.out.println("My name is wangyang!" + this.name);
}
}
类似的WY类也实现了这个接口
package com.siti.spring20160305;
public class WY implements Person{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void printName() {
System.out.println("My name is wy!" + this.name);
}
}
在配置文件中,设置为抽象Bean,即abstract="true",这样在进行引用的时候,引用父Bean的信息,就用parent="*****"。
<?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中直接配置参数,如果说像下面两个bean来说有一部分重复了,
那么可以直接拿出来作为抽象的bean,然后让下面两个bean引用即可,这样的好处就是使得配置文件不至于臃肿,
提高可维护性。
-->
<!--
<bean name = "wangyang" class = "com.siti.spring20160305.WangYang">
<property name="name" value="> wangyang"></property>
</bean>
<bean name = "wy" class = "com.siti.spring20160305.WY">
<property name="name" value="> wy"></property>
</bean>
-->
<bean id = "commonProperty" abstract="true">
<property name="name" value="> commonProperty"></property>
</bean>
<bean name = "wangyang" class = "com.siti.spring20160305.WangYang" parent="commonProperty">
</bean>
<bean name = "wy" class = "com.siti.spring20160305.WY" parent="commonProperty">
</bean>
</beans>
测试代码
package com.siti.spring20160305;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
/**
* @param args
*/
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext20160305.xml");
Person wangyang = context.getBean("wangyang", Person.class);
wangyang.printName();
Person wy = context.getBean("wy", Person.class);
wy.printName();
}
}
工厂Bean
在前面的博客中提到过工厂,但是之前的工厂是工厂模式,现在的这里是特殊些的Bean,他必须实现FactoryBean接口,实现其方法,程序通过getBean获取实例的时候,他会返回实现的方法中getObject方法的返回值。
三大方法:
1. getObject():负责返回该Bean的实例
2. getObjectType():返回Bean生成的java实例的实现类。
3. isSingleton():是不是单例模式。
该类实现FactoeyBean接口实现其方法,如下:
package com.siti.spring20160305factorybean;
import java.lang.reflect.Field;
import org.springframework.beans.factory.FactoryBean;
public class WangYang implements FactoryBean<Object>{
private String targetClass;
private String targetField;
public String getTargetField() {
return targetField;
}
public void setTargetField(String targetField) {
this.targetField = targetField;
}
public String getTargetClass() {
return targetClass;
}
public void setTargetClass(String targetClass) {
this.targetClass = targetClass;
}
@Override
public Object getObject() throws Exception {
// 反射通过名称查找该类
Class<?> clazz = Class.forName(this.targetClass);
// 反射类的属性
Field field = clazz.getField(targetField);
// 静态变量
return field.get(null);
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
配置文件
<?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 name = "wangyang" class = "com.siti.spring20160305factorybean.WangYang">
<property name="targetClass" value="java.lang.Long"></property>
<property name="targetField" value="MAX_VALUE"></property>
</bean>
</beans>
测试代码:
package com.siti.spring20160305factorybean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext20160305.xml");
System.out.println(context.getBean("wangyang"));
}
}
获取Bean的id
在某些情况下可能会需要提前知道Bean的id才行,那么下面这个例子会展示怎么利用BeanNameAware接口,拿到配置文件中配置的id。
在配置文件实例化Bean的时候,检测到某个类实现了BeanNameAware这个接口,那么会通过setBeanName方法将Bean的id作为参数beanName注入到这个类的属性中去。
实现BeanNameAware接口,实现它的方法。
package com.siti.spring20160305beanid;
import org.springframework.beans.factory.BeanNameAware;
public class WangYang implements BeanNameAware{
private String beanName;
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void printBeanName(){
System.out.println(this.beanName);
}
}
配置文件中将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 name = "wangyang" class = "com.siti.spring20160305beanid.WangYang"></bean>
</beans>
对上面的阐述进行测试:
package com.siti.spring20160305beanid;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.siti.spring20160227.Person;
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext20160305.xml");
WangYang wy = context.getBean("wangyang", WangYang.class);
wy.printBeanName();
}
}
这里会拿到wy实例的id的。