Spring容器启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。
Bean配置信息时Bean的元数据信息,它由一下4个方面组成:
1. Bean的实现类;
2. Bean的属性信息,如数据源的连接数,用户名;
3. Bean的依赖关系,Spring根据依赖关系配置完成Bean之间的装配;
4. Bean的行为配置,如生命周期及个过程的回调函数等。
Bean元数据信息在Spring容器中的内部对应物是由一个个BeanDefinition形成的Bean注册表,Spring实现了Bean元数据信息内部和外部表示的解耦。
Bean配置信息定义了Bean的实现和依赖关系,Spring容器根据各种形式的Bean配置信息在容器内部建立Bean定义注册表,然后根据注册表加载、实例化Bean,并建立Bean和Bean的依赖关系,最后将这些就绪的Bean放到Bean缓冲池中,以供外层的应用程序进行调用。
一、依赖注入
1. 属性注入
a. 属性注入即通过setXxx()方法注入Bean的属性值或依赖对象,属性注入方式具有可选择性和灵活性高的优点。
b. 属性注入要求Bean提供一个默认的构造函数,并为需要注入的属性提供对应的Setter方法。
c. Spring先调用Bean的默认构造函数实例化Bean对象,然后通过反射的方式调用Setter方法。
package spring.ioc.demo1; public class Car { private String brand; private String color; private int maxSpeed; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } public String toString(){ return "the car is:"+ getBrand() + ", color is:" +getColor() +", maxspeed is:"+getMaxSpeed(); } public Car() { } public Car(String brand, String color, int maxSpeed) { this.brand = brand; this.color = color; this.maxSpeed = maxSpeed; } public void introduce() { System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:" + maxSpeed); } }
<bean id="car1" class="spring.ioc.demo1.Car"
<property name="brand"><value>spring注入-红旗001</value></property>
<property name="color"><value>spring注入-紫色</value></property>
<property name="maxSpeed"><value>520</value></property>
</bean>
2.构造函数注入
a. 它保证一些必要的属性在Bean实例化时就得到设置,它保证Bean实例化以后就可以使用;
b. Bean必须提供带参的构造函数。
public class Car{ ....... public Car(String brand, String color, int maxSpeed) { this.brand = brand; this.color = color; this.maxSpeed = maxSpeed; } ....... }
<bean id="car1" class="spring.ioc.demo1.Car"
<construcotr-arg type="java.lang.String"><value>spring注入-红旗001</value></construcotr-arg>
<construcotr-arg type="java.lang.String"><value>spring注入-紫色</value></construcotr-arg>
<construcotr-arg type="double"><value>520</value></construcotr-arg>
</bean>
也可以通过索引的方式进行配置:
<bean id="car1" class="spring.ioc.demo1.Car"
<construcotr-arg index="0"><value>spring注入-红旗001</value></construcotr-arg>
<construcotr-arg index="1"><value>spring注入-紫色</value></construcotr-arg>
<construcotr-arg index="2"><value>520</value></construcotr-arg>
</bean>
但是为了避免潜在的配置歧义,例如Bean存在多个构造函数,我们最好还是设置一下参数的Type.
3. 引用其他Bean
package spring.ioc.iocbean; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import spring.ioc.demo1.Car; public class Boss { private List<String> favorites = new ArrayList<String>(); private Car car; private Map<String, Car> jobs = new HashMap<String, Car>(); private Properties mails = new Properties(); public Properties getMails() { return mails; } public void setMails(Properties mails) { this.mails = mails; } public Map<String, Car> getJobs() { return jobs; } public void setJobs(Map<String, Car> jobs) { this.jobs = jobs; } public List<String> getFavorites() { return favorites; } public void setFavorites(List<String> favorites) { this.favorites = favorites; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } }
<bean id="car1" class="spring.ioc.demo1.Car" p:brand="spring注入-红旗001" p:color="spring注入-紫色" p:maxSpeed="520" /> <bean id="boss" class="spring.ioc.iocbean.Boss"> <property name="car"> <ref bean="car1"></ref> </property> </bean>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Boss boss = ctx.getBean("boss",Boss.class); System.out.println(boss.getCar()); }
4. null值
如果用户想为car的brand属性注入一个null值,那么必须如下进行配置:
<bean id="car1" class="spring.ioc.demo1.Car" <property name="brand"><value><null/></value></property> <property name="color"><value>spring注入-紫色</value></property> <property name="maxSpeed"><value>520</value></property> </bean>
5. 集合类型属性-List
<bean id="boss" class="spring.ioc.iocbean.Boss">
<property name="favorites">
<list>
<value>电影</value>
<value>音乐</value>
</list>
</property>
</bean>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Boss boss = ctx.getBean("boss",Boss.class); List<String> myLove = boss.getFavorites(); Iterator<String> it = myLove.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
输出:
电影
音乐
6. 集合类型属性-Map
<bean id="boss" class="spring.ioc.iocbean.Boss">
<property name="jobs">
<map>
<entry>
<key><value>getCar</value></key>
<ref bean="car1" />
</entry>
</map>
</property>
</bean>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Boss boss = ctx.getBean("boss",Boss.class); Map<String, Car> map =boss.getJobs(); Car car = map.get("getCar"); System.out.println(car.getColor()); }
输出:spring注入-紫色
7. 集合类型属性-Properties
Properties类型可以看成是Map类型的特列,Map类型的key和value可以为任何类型,而Properties只能为字符串。
<bean id="boss" class="spring.ioc.iocbean.Boss">
<property name="mails">
<props>
<prop key="jobMail">libininfo@360buy.com</prop>
<prop key="lifeMail">nicholaslee@126.com</prop>
</props>
</property>
</bean>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); Boss boss = ctx.getBean("boss",Boss.class); Properties pro = boss.getMails(); System.out.println(pro.get("lifeMail")); }
输出:nicholaslee@126.com
8. 通过util命名空间配置集合类型的Bean
如果希望配置一个集合类型的Bean,而非一个集合类型的属性,则可以通过util命名空间进行配置。
需要再Spring配置文件头中应用util命名空间的声明:
xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd ">
下面配置一个List类型的Bean,可以通过list-class显示指定List的实现类。
<!-- 配置一个集合类型的Bean,不是一个集合类型的属性 -->
<util:list id="favoriteList1" list-class="java.util.LinkedList">
<value>看报</value>
<value>赛车</value>
</util:list>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); //读取一个集合类型的Bean,不是一个集合类型的属性 List<String> testList = (LinkedList)ctx.getBean("favoriteList1"); Iterator<String> itList = testList.iterator(); while(itList.hasNext()){ System.out.println(itList.next()); } }
输出:
看报
赛车
9. lookup方法注入
Spring容器拥有复写Bean方法的能力,为Bean动态创建子类或实现类。
我们可以在singleton的Boss中注入prototype的Car,并且保证每次返回的Car对象都是最新的。
package spring.ioc.iocbean; import spring.ioc.demo1.Car; public interface MagicBoss { Car getCar(); }
下面我们不编写任何实现类,仅通过配置为该接口提供动态的实现,让getCar接口每次都返回心的Car Bean.
<bean id="car1" class="spring.ioc.demo1.Car" scope="prototype" p:brand="spring注入-红旗001" p:color="spring注入-紫色" p:maxSpeed="520" /> <!-- lookup方法注入 --> <bean id="magicBoss" class="spring.ioc.iocbean.MagicBoss"> <lookup-method name="getCar" bean="car1"/> </bean>
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); //lookup方法注入 代替实现BeanFactoryAware接口或者ApplicationContextAware接口 MagicBoss magicBos = ctx.getBean("magicBoss",MagicBoss.class); System.out.println("lookup-method:"+magicBos.getCar()); }
输出:lookup-method:the car is:spring注入-红旗001, color is:spring注入-紫色, maxspeed is:520
10. 实现ApplicationContextAware/BeanFactoryAware 接口
加载Spring配置文件时,如果Spring配置文件中所定义的Bean类实现了ApplicationContextAware 接口,
那么在加载Spring配置文件时,会自动调用ApplicationContextAware 接口中的public void setApplicationContext(ApplicationContext context) 方法,获得ApplicationContext对象,前提必须在Spring配置文件中指定该类
<!-- ApplicationContextAware接口方式注入 -->
<bean id="magicBossImpl2" class="spring.ioc.iocbean.MagicBossImpl2" />
package spring.ioc.iocbean; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import spring.ioc.demo1.Car; public class MagicBossImpl2 implements MagicBoss,ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { this.applicationContext = arg0; } @Override public Car getCar() { return applicationContext.getBean("car1",Car.class); } }
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); //实现ApplicationContextAware接口方式 MagicBossImpl2 magicBos2 = ctx.getBean("magicBossImpl2",MagicBossImpl2.class); System.out.println("ApplicationContextAware:"+magicBos2.getCar()); }
输出:ApplicationContextAware:the car is:spring注入-红旗001, color is:spring注入-紫色, maxspeed is:520
一般很少使用这种方法来每次都返回一个新的Bean,因为这样就和Spring框架耦合了,推荐使用lookup方法的注入方式。
11. 方法替换
用户可以使用某个Bean的方法去替换另一个Bean中的方法。
package spring.ioc.iocbean; import spring.ioc.demo1.Car; public class Boss1 { public Car getCar(){ Car car = new Car(); car.setBrand("垃圾车"); return car; } }
package spring.ioc.iocbean; import java.lang.reflect.Method; import org.springframework.beans.factory.support.MethodReplacer; import spring.ioc.demo1.Car; public class Boss2 implements MethodReplacer { @Override public Object reimplement(Object arg0, Method arg1, Object[] arg2) throws Throwable { Car car = new Car(); car.setBrand("蝙蝠车"); return car; } }
Boss2实现了MethodReplacer接口,Spring将利用接口方法去替换目标Bean中的方法。
<!-- MethodReplacer掉包 --> <bean id="boss1" class="spring.ioc.iocbean.Boss1"> <replaced-method name="getCar" replacer="boss2" /> </bean> <bean id="boss2" class="spring.ioc.iocbean.Boss2" />
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); //MethodReplacer掉包 Boss1 boss1 = ctx.getBean("boss1",Boss1.class); System.out.println(boss1.getCar().getBrand()); }
输出:蝙蝠车
12. Bean的继承关系
如果多个bean存在相同的配置信息,Spring允许我们顶一个父bean,子bean将自动继承父bean的配置信息。
<bean id="car1" class="spring.ioc.demo1.Car" p:brand="spring注入-红旗001" p:color="spring注入-紫色" p:maxSpeed="520" /> <!-- childCar 继承bean:car1 --> <bean id="childCar" class="spring.ioc.demo1.Car" parent="car1" p:maxSpeed="1314" />
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); //Bean的继承 Car childCar = ctx.getBean("childCar",Car.class); System.out.println("Bean的继承:"+childCar); } 输出:Bean的继承:the car is:spring注入-红旗001, color is:spring注入-紫色, maxspeed is:1314
说明:如果子bean提供了父bean已有的配置信息,子bean的配置信息将覆盖父bean的配置信息。
以上就是在IoC容器中装配Bean的常用方法,还有别的形式大家可以跟评论。