1、bean的基本定义和bean别名
2、容器中bean的作用域
singleton:单例模式,在整个spring IoC容器中,singleton作用域的bean将只生成一个实例。
prototype:每次通过容器的getBean()方法获取prototype作用域的bean时,都将产生一个新的bean实例。
request:对于一次HTTP请求,request作用域的bean将只生成一个实例,这意味着,在同一次HTTP请求内,程序每次请求该bean,得到的总是同一个实例。只有在Web应用中使用spring时,该作用域才真正的有效。
session:对于一次HTTP会话,sesion作用域的bean将只生成一个实例,这意味着,在同一次HTTP会话内,程序每次请求该bean,得到的总是同一个实例。只有在Web应用中使用spring时,该作用域才真正的有效。
global session:每个全局的HTTP Session对应一个bean实例。在典型的情况下,仅在使用portlet context的时候有效。只有在Web应用中使用spring时,该作用域才真正的有效。
比较常用的是singleton和prototype。对于singleton作用域的bean,每次请求该bean都将获得相同的实例。容器负责跟踪bean实例的状态,负责维护bean实例的生命周期行为;对于prototype作用域的bean,程序每次请求该id的bean,spring都会新建一个bean实例,然后返回给程序。这种情况下,spring容器仅仅使用new关键字创建bean实例,一旦创建成功,容器就不再跟踪实例,也不会维护bean实例的状态。
如果不指定bean的作用域,spring容器默认使用singleton作用域。
spring配置文件通过scope属性指定bean的作用域,该属性可以接受singleton、prototype、request、session、globalSession五个值。
3、request作用域
4、session作用域
5、配置依赖
在依赖注入方式总结的时候,我们总结类两种依赖注入方式:
设值注入:通过<property.../>元素驱动spring执行setter方法。
构造注入:通过<constructor-arg.../>元素驱动spring执行带参数的构造器。
对这两种设值方式的底层实现模拟:
Person.java
package com.lfy.bean; public class Person { private String name; private int age; /** * 定义一个无参构造器 */ public Person() {} /** * 定义一个带参构造器 * @param name * @param age 构造器使用Integer,class字段属性是int */ public Person(String name,Integer age) { this.name=name; this.age=age; } public void sayHello(String name) { System.out.println(name+",Hello.Nice to see you."); } public void selfIntroduction() { System.out.println("Hello,I am "+name+".I am "+age); } }
ReflexTest.java
package com.lfy.main; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import com.lfy.bean.Person; /** * java反射的应用 * @author lfy * */ public class ReflexTest { public static void main(String[] args) { /** * spring设值注入底层代码实现简单例子 */ try { Class targetClass=Class.forName("com.lfy.bean.Person"); try { Object bean=targetClass.newInstance(); try { String name="lfy"; Method targetMethod=targetClass.getMethod("sayHello", name.getClass());//这里演示没有使用Person.name的setter方法,但道理一样的 try { targetMethod.invoke(bean, name); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } /** * spring构造注入底层实现简单例子 */ try { Class targetClass=Class.forName("com.lfy.bean.Person"); try { String param1="lfy"; Integer param2=21; Constructor targetCtr=targetClass.getConstructor(param1.getClass(),param2.getClass()); try { //以指定构造器创建bean实例 Object bean=targetCtr.newInstance(param1,param2); Person p=(Person)bean; p.selfIntroduction(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
运行结果:
6、自动装配注入合作者bean(即:被依赖bean),缺点是明显降低了配置文件的可读性
<beans.../>元素下是default-autowire属性,<bean.../>元素下是autowire,它们可接受的值有:
no:不使用自动装配。bean依赖必须通过ref元素定义,是默认配置。
byName:根据setter方法名进行自动装配。spring容器查找容器中的全部bean,找出其id与setter方法名去掉set前缀,并小写字母后同名的bean来完成注入。如果没有匹配到任何bean实例,spring不会进行任何注入。
byType:根据setter方法的形参类型来自动装配。spring容器查找容器中的全部bean,如果正好有一个bean类型与setter方法的形参类型匹配,就自动注入这个bean;如果找到多个这样的bean,就抛出一个异常;如果没有找到这样的bean,则什么都不发生,setter方法不会被调用。
constructor:与byType类似,区别是用于自动匹配构造器的参数。如果容器不能恰好找到一个与构造器参数类型匹配的bean,则会抛出一个异常。
autodetect:spring容器根据bean内部结构,自行决定使用constructor或byType策略。如果找到一个默认的构造器,那么就会应用byType策略。
7、注入嵌套bean
如果某个bean所依赖的bean不想被spring容器直接访问,则可以使用嵌套bean。
将<bean.../>配置成<property.../>或<constructor-args.../>的子元素,则该bean仅作为设值注入、构造注入的参数,该bean就叫做嵌套bean。由于容器不能获取嵌套bean,故无需配置嵌套bean的id属性。
8、注入集合值
如果要被注入的值是集合类型,无论设值注入,还是构造注入,则可以使用集合元素<list.../>、<set.../>、<map.../>和<props.../>分别来设值类型为List、Set、Map和Properties的集合参数值。
看个例子:
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- spring配置文件的根元素,使用spring-beans-4.0.xsd语义约束 --> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="stoneAxe" class="com.lfy.impl.StoneAxe"/> <bean id="steelAxe" class="com.lfy.impl.SteelAxe"/> <bean id="chinese" class="com.lfy.impl.Chinese"> <!-- List<String> --> <property name="schools"> <list> <!-- 每个value、ref、bean...都配置一个List元素 --> <value>小学</value> <value>中学</value> <value>大学</value> </list> </property> <!-- Map --> <property name="scores"> <map> <!-- 每个entry代表一个key-value对 --> <entry key="数学" value="87"/> <entry key="英语" value="89"/> <entry key="语文" value="82"/> </map> </property> <!-- Map<String,Axe> --> <property name="phaseAxes"> <map> <entry key="原始社会" value-ref="stoneAxe"/> <entry key="农业社会" value-ref="steelAxe"/> </map> </property> <!-- Properties --> <property name="health"> <props> <!-- 每个prop元素配置一个属性项,其中key指定属性名 --> <prop key="血压">正常</prop> <prop key="血压">175</prop> </props> </property> <!-- Set --> <property name="axes"> <set> <!-- 每个value、ref、bean...都配置一个Set元素 --> <value>普通的字符串</value> <bean class="com.lfy.impl.SteelAxe"/> <ref bean="stoneAxe"/> <list> <value>20</value> <!-- 再次为List配置一个Set集合作为元素 --> <set> <value type="int">30</value> </set> </list> </set> </property> <!-- String[] --> <property name="books"> <list> <!-- 每个value、ref、bean...都配置一个数组元素 --> <value>疯狂java讲义</value> <value>疯狂Android讲义</value> <value>轻量级java ee企业应用实战</value> </list> </property> </bean> </beans>
stoneAxe.java
package com.lfy.impl; import com.lfy.bean.Axe; public class StoneAxe implements Axe { @Override public String chop() { return "石斧砍柴好慢"; } }
steelAxe.java
package com.lfy.impl; import com.lfy.bean.Axe; public class SteelAxe implements Axe { @Override public String chop() { return "钢斧砍柴真快"; } }
Chinese.java
package com.lfy.impl; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import com.lfy.bean.Axe; import com.lfy.bean.Person; public class Chinese implements Person { private Axe axe; private List<String> schools; private Map scores; private Map<String,Axe> phaseAxes; private Properties health; private Set axes; private String[] books; public Chinese() { System.out.println("spring实例化主调bean:Chinese实例..."); } //设值注入所需的setter方法 public void setAxe(Axe axe) { this.axe=axe; } public void setSchools(List schools) { this.schools=schools; } public void setScores(Map scores) { this.scores=scores; } public void setPhaseAxes(Map<String,Axe> phaseAxes) { this.phaseAxes=phaseAxes; } public void setHealth(Properties health) { this.health=health; } public void setAxes(Set axes) { this.axes=axes; } public void setBooks(String[] books) { this.books=books; } @Override public void useAxe() { //调用axe的chop()方法 //表明Person对象依赖于axe对象 System.out.println(axe.chop()); } public void test() { System.out.println(schools); System.out.println(scores); System.out.println(phaseAxes); System.out.println(health); System.out.println(axes); System.out.println(Arrays.toString(books)); } }
springTest.java
package com.lfy.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lfy.impl.Chinese; public class SpringTest { public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); Chinese c=ctx.getBean("chinese", Chinese.class); c.test(); } }
运行结果:
9、组合属性的设值
举个例子,猫组合了一个主人相关的属性:
Chinese.java
package com.lfy.impl; import com.lfy.bean.Person; public class Chinese implements Person { //姓名 private String name; public String getName() { return name; } public void setName(String name) { this.name=name; } }
Cat.java
package com.lfy.impl; import com.lfy.bean.Animal; public class Cat implements Animal { //猫的主人是个中国人 private Chinese chinese=new Chinese(); public Chinese getChinese() { return chinese; } }
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- spring配置文件的根元素,使用spring-beans-4.0.xsd语义约束 --> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <bean id="cat" class="com.lfy.impl.Cat"> <property name="chinese.name" value="lfy"/> </bean> </beans>
SpringTest.java
package com.lfy.main; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lfy.impl.Cat; import com.lfy.impl.Chinese; public class SpringTest { public static void main(String[] args) { ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml"); Cat c=ctx.getBean("cat", Cat.class); System.out.println("猫的主人的名字叫做:"+c.getChinese().getName()); } }
运行结果: