Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
来源:互联网 发布:石家庄seo公司 编辑:程序博客网 时间:2024/05/22 12:39
Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
InitializingBean
package research.spring.beanfactory.ch4;import org.springframework.beans.factory.InitializingBean;public class LifeCycleBean implements InitializingBean{ public void afterPropertiesSet() throws Exception { System.out.println("LifeCycleBean initializing..."); }}
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="lifeBean" class="research.spring.beanfactory.ch4.LifeCycleBean"> bean>beans>
package research.spring.beanfactory.ch4; import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource; public class LifeCycleTest { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource(
"research/spring/beanfactory/ch4/context.xml")); factory.getBean("lifeBean"); } }
SHAPE /* MERGEFORMAT
装配bean的合作者
查看bean是否实现InitializingBean接口
调用afterPropertiesSet方法
init-method
package research.spring.beanfactory.ch4;public class LifeCycleBean{ public void init(){ System.out.println("LifeCycleBean.init..."); }}
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="lifeBean" class="research.spring.beanfactory.ch4.LifeCycleBean"
init-method="init"> bean>beans>
final protected void init() throws Exception{
System.out.println("init method...");
if(true) throw new Exception("init exception");
//……//在一个bean的合作者设备完成后,执行一个bean的初始化方法。protected void invokeInitMethods(String beanName, Object bean, RootBeanDefinition mergedBeanDefinition)
throws Throwable { //判断bean是否实现了InitializingBean接口 if (bean instanceof InitializingBean) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } //调用afterPropertiesSet方法 ((InitializingBean) bean).afterPropertiesSet(); }//判断bean是否定义了init-methodif(mergedBeanDefinition!=null&&mergedBeanDefinition.getInitMethodName() != null) { //调用invokeCustomInitMethod方法来执行init-method定义的方法invokeCustomInitMethod(beanName, bean, mergedBeanDefinition.getInitMethodName());}}//执行一个bean定义的init-method方法protected void invokeCustomInitMethod(String beanName, Object bean, String initMethodName) throws Throwable { if (logger.isDebugEnabled()) { logger.debug("Invoking custom init method '" + initMethodName + "' on bean with name '" + beanName + "'"); } //使用方法名,反射Method对象 Method initMethod = BeanUtils.findMethod(bean.getClass(), initMethodName, null); if (initMethod == null) { throw new NoSuchMethodException(
"Couldn't find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'"); } //判断方法是否是public if (!Modifier.isPublic(initMethod.getModifiers())) { //设置accessible为true,可以访问private方法。 initMethod.setAccessible(true); } try { //反射执行这个方法 initMethod.invoke(bean, (Object[]) null); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } }//………..
Spring内核研究-管理bean之间的关系三(自动装配)
Spring BeanFactory提供了类似pico container中自动装配组件依赖的对象的功能。自动装配能应用在每个组件上,可以为一些组件定义自动装配,而另一些组件则不使用。
no
byName
SHAPE /* MERGEFORMAT
按照bean定义的名称自动装配
SHAPE /* MERGEFORMAT
这个Bean将被注入到dao中
byType
SHAPE /* MERGEFORMAT
按照bean定义的类型自动装配
SHAPE /* MERGEFORMAT
这个Bean将被注入到dao中
SHAPE /* MERGEFORMAT
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dao' defined in class path resource [research/spring/beanfactory/ch3/context.xml]: Unsatisfied dependency expressed through bean property 'database': There are 2 beans of type [class research.spring.beanfactory.ch3.Database] for autowire by type. There should have been 1 to be able to autowire property 'database' of bean 'dao'...
constructor其实时按byType的方式进行构造函数的注入。
SHAPE /* MERGEFORMAT
按照bean定义的类型自动装配
constructor装配方式不关心构造参数的顺序,无论构造函数参数的顺序如何Spring都会按类型匹配到正确的合作者进行注入。
autodetect
Spring内核研究-管理bean之间的关系二(自动依赖检查)
package research.spring.beanfactory.ch3;public class Dao { private String name; public void setName(String name) { this.name = name; } }
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao"> </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean></beans>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" dependency-check="all" > </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean></beans>
- none(默认)
- simple
- objects
- all
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" dependency-check="objects" > </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean></beans>
- 不能对构造函数中的参数进行检查。
- 即使属性中有默认值,只要包含了set方法,那么dependency-check仍然需要检查Spring中是否配置了这个属性。
package research.spring.beanfactory.ch3; public class Dao { private Database database; private String name="chenjie";//dependency-check仍然会检查这个属性是否配置注入 public void setName(String name) { this.name = name; } public void setDatabase(Database database) { this.database = database; } }
Spring内核研究-管理bean之间的关系一(depends-on)
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" depends-on="database"> </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean> </beans>
DAO depend-on Database时,也可以在DAO上定义setDatabase方法来接收一个Database的实例。这样Sping会保证DAO创建前先创建Database实例,然后在把实例化DAO后调用DAO的setDatabase方法把刚才创建的Database的实例注入给DAO。前提条件时Database必须定义成单例的。否则Spring在DAO depend-on Database时会创建一个Database的实例,在DAO.setDatabase时又会创建Database另外的一个实例。这种情况可能不是你想要的,而且很可能会造成比较隐蔽的错误。
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" depends-on="database "> <property name="database"> <ref bean="database"></ref> </property> </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean> </beans>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="dao" class="research.spring.beanfactory.ch3.Dao" depends-on="database"> <constructor-arg> <ref bean="database"></ref> </constructor-arg> </bean> <bean id="database" class="research.spring.beanfactory.ch3.Database"> </bean> </beans>
Spring允许Bean和Bean依赖的Bean(合作者)上同时定义depends-on。比如A depends-on B && B depends-on C && C depends-on D。下面这样定义是合法的。Sping实例化他们的顺序是D->C->B->A。
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="a" class="research.spring.beanfactory.ch3.A" depends-on="b" /><bean name="b" class="research.spring.beanfactory.ch3.B" depends-on="c" /><bean name="c" class="research.spring.beanfactory.ch3.C" depends-on="D" /><bean name="d" class="research.spring.beanfactory.ch3.D" /> </beans>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="a" class="research.spring.beanfactory.ch3.A" depends-on="b" /><bean name="b" class="research.spring.beanfactory.ch3.B" depends-on="c" /><bean name="c" class="research.spring.beanfactory.ch3.C" depends-on="D" /><bean name="d" class="research.spring.beanfactory.ch3.D" depends-on="A"/> </beans>
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="a" class="research.spring.beanfactory.ch3.A" depends-on="d,c,b" /><bean name="b" class="research.spring.beanfactory.ch3.B" /><bean name="c" class="research.spring.beanfactory.ch3.C" /><bean name="d" class="research.spring.beanfactory.ch3.D" /> </beans>
上面的例子中A的实例化需要先实例化D,C,B。Spring会按照depend-on中定义的顺序来处理Bean。在这个例子里Spring实例化对象的顺利是D->C->B->A。虽然实例化对象的顺序和前面“A depends-on B && B depends-on C && C depends-on D”的情况一下,但是这里的意义是完全不同的。不能用“A depends-on D,C,B”代替“A depends-on B && B depends-on C && C depends-on D”。
depends-on是一个非常又用的功能,借助depends-on我们可以管理那些依赖关系不明显或者没有直接依赖关系的对象。Spring内核研究-通过工厂注入
静态工厂注入
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao"
factory-method="getInstance" / >beans>
package research.spring.beanfactory.ch2;public class UserDao { public static UserDao getInstance() { return new UserDao("static factory method"); } private String name = ""; public UserDao(String name) { this.name = name; } public void create() { System.out.println("create user from - " + name); }}
package research.spring.beanfactory.ch2;
import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource; public class Test { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource(
"research/spring/beanfactory/ch2/context.xml")); UserManager manager=(UserManager) factory.getBean("userManager"); manager.createUser(); } }
create user from - static factory method
- 静态工厂方法上不能有参数,也不能在Spring种定义静态工厂方法的参数。
- 静态工厂方法只能是public的,不能是private或protected的。
- 静态工厂方法不能和构造函数注入一起使用。下面的定义时不能正常工作的:
package research.spring.beanfactory.ch2; import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource; public class Test { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource(
"research/spring/beanfactory/ch2/context.xml")); UserManager manager=(UserManager) factory.getBean("userManager"); manager.createUser(); } }
实例工厂注入
修改context.xml:package research.spring.beanfactory.ch2; public class UserDaoFactory{ public UserDao getUserDao(){ return new UserDao("UserDaoFactory"); }}
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao"
factory-bean="userDaoFactory" factory-method="getUserDao" > bean> <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.UserDaoFactory"> bean>beans>
- factory-bean定义了工厂Bean
- factory-method定义了工厂方法
- 静态工厂方法上不能有参数,也不能在Spring种定义静态工厂方法的参数。
- 静态工厂方法只能是public的,不能是private或protected的。
- 静态工厂方法不能和构造函数注入一起使用。
- 实例工厂方法不能是静态的,而静态工厂方法必须是静态的。
Spring内核研究-Lookup方法注入
Lookup方法注入
package research.spring.beanfactory.ch2; public class UserDao { private String name=""; public UserDao(String name){ this.name=name; } public void create(){ System.out.println("create user from - "+name); } }
package research.spring.beanfactory.ch2; public class UserManager { public UserDao getUserDao() { return new UserDao("UserManager.getUserDao()"); } public void createUser() { UserDao dao = getUserDao(); //通过getUserDao获得userDao dao.create(); }}
context.xmlpackage research.spring.beanfactory.ch2;import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource; public class LookupMethodTest { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource("research/spring/beanfactory/ch2/context.xml")); UserManager manager=(UserManager) factory.getBean("userManager"); manager.createUser(); //create a User }}
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> bean> <bean name="userDao class="research.spring.beanfactory.ch2.UserDao" > bean>beans>
运行LookupMethodTest你会看到屏幕输入” create user from - UserManager.getUserDao()”。
在这个场景中我们就可以利用Spring提供的“Lookup方法”来替换原有的getUserDao方法,实现自动获取userDao的功能。修改context.xml:
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao" > <constructor-arg> <value>lookup methodvalue> constructor-arg> bean> <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.UserDaoFactory"> bean>beans>
再次运行LookupMethodTest你会看到不同的输出结果“create user from - lookup method”。字符串“lookup method”是通过构造函数注入给userDao的。原来的userManager.java并没有作任何修改,仍然是通过UserDao dao = getUserDao();来获得userDao的。这说明Spring已经替换了原有的getUserDao方法的实现,当执行getUserDao时Spring会在容器中寻找指定的Bean,并返回这个Bean。
Lookup方法的工作机制
package research.spring.beanfactory.ch2;import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource;public class LookupMethodTest { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource(
"research/spring/beanfactory/ch2/context.xml")); UserManager manager=(UserManager) factory.getBean("userManager"); System.out.println(manager.toString()); //打印userManager的信息 manager.createUser(); //create a User }}
<bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> <lookup-method name="getOtherDao" bean="otherDao" />bean>
修改UserManager:
package research.spring.beanfactory.ch2; public class UserManager { private UserDao dao; public void setDao(UserDao dao) { this.dao = dao; } public UserDao getUserDao(String daoName) { return new UserDao("UserManager.getUserDao()"); } public void createUser() { UserDao dao = getUserDao(“userDao”); //通过getUserDao获得userDao dao.create(); }}
- 方法不能是private的,但可以是protected的。
- 方法不能是静态的。
在抽象类和接口上应用Lookup方法
package research.spring.beanfactory.ch2;public abstract class Factory { public abstract UserDao getProduct();}
package research.spring.beanfactory.ch2; public class UserDaoFactory extends Factory{ public UserDao getProduct(){ return new UserDao("UserDaoFactory"); }}
new UserDaoFactory().getProduce();
package research.spring.beanfactory.ch2; public abstract class Factory { public abstract Object getProduct();}
xml version="1.0" encoding="UTF-8"?>DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <bean name="userManager" class="research.spring.beanfactory.ch2.UserManager"> <lookup-method name="getUserDao" bean="userDao" /> bean> <bean name="userDao" class="research.spring.beanfactory.ch2.UserDao" > <constructor-arg> <value>lookup methodvalue> constructor-arg> bean> <bean name="userDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false"> <lookup-method name="getProduct" bean="userDao" /> bean>beans>
package research.spring.beanfactory.ch2; import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.ClassPathResource; public class LookupMethodTest { public static void main(String[] args) { XmlBeanFactory factory=new XmlBeanFactory(new ClassPathResource(
"research/spring/beanfactory/ch2/context.xml")); //获得抽象工厂 Factory abstractFactory=(Factory) factory.getBean("userDaoFactory"); UserDao userDao=(UserDao) abstractFactory.getProduct(); System.out.println(userDao.toString()); userDao.create(); } }
<bean name="userDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false"> <lookup-method name="getProduct" bean="userDao" /> bean> <bean name="documentDaoFactory" class="research.spring.beanfactory.ch2.Factory" singleton="false"> <lookup-method name="getProduct" bean="documentDao" /> bean>
Spring内核研究-set方法注入和构造函数注入
- Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
- Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
- Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
- Spring内核研究-管理bean的声明周期一(InitializingBean和init-method) .
- Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
- Spring的InitializingBean和init-method
- Spring的InitializingBean和init-method
- Spring的InitializingBean和init-method
- Spring的InitializingBean和init-method
- 浅谈Spring的InitializingBean和init-method
- Spring的InitializingBean和init-method
- Spring InitializingBean和init-method
- Spring InitializingBean和init-method
- Spring InitializingBean和init-method
- Spring InitializingBean和init-method
- Spring InitializingBean和init-method
- Spring InitializingBean和init-method
- Spring InitializingBean和init-method
- JSF+MYFACES+HIBERNATE+SPRING+ACEGI+A4J
- 浏览器不能正常调用Media Player播放网上音乐的解决办法
- JUnit重装上阵
- 做编辑还是做程序员?[编辑的技术培训FAQ]
- spring代理
- Spring内核研究-管理bean的声明周期一(InitializingBean和init-method)
- [转]QQ铭
- 又到了1月8日
- MDF文件在SQL Server中的恢复技术
- STL中map与hash_map容器的选择
- SCA/SDO走向成熟 将正式成为SOA标准
- C#中PictureBox控件的Image转存数据库
- SQL 存储过程
- JNDI的学习