spring开发提倡接口编程,配合DI技术可以达到层与层间的解耦
1、体验spring的DI配合接口编程,完成一个字母大小写转换的案例:
思路:
1)创建一个接口ChangeLetter
package com.cdtax.inter; public interface ChangeLetter { //声明一个方法 public String change(); }
package com.cdtax.inter; public class UpperLetter implements ChangeLetter { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override public String change() { //把小写字母->大写 return(str.toUpperCase()); } }
package com.cdtax.inter; public class LowwerLetter implements ChangeLetter { private String str; public String getStr() { return str; } public void setStr(String str) { this.str = str; } @Override public String change() { return str.toLowerCase(); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="changeLetter" class="com.cdtax.inter.UpperLetter"> <property name="str"> <value>abcde</value> </property> </bean> <!-- <bean id="changeLetter" class="com.cdtax.inter.LowwerLetter"> <property name="str" value="ABDERTY"></property> </bean> --> </beans>注意这里注释了一个bean,id相同
package com.cdtax.inter; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App1 { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("com/cdtax/inter/beans.xml"); //获取,不用接口 UpperLetter changeLetter = (UpperLetter)ac.getBean("changeLetter"); System.out.println(changeLetter.change()); } }这时不通过接口进行的调用,如果我们要使用LowwerLetter,就要修改上面的程序。
使用接口:
package com.cdtax.inter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App1
{
public static void main(String[] args)
{
ApplicationContext ac = new ClassPathXmlApplicationContext("com/cdtax/inter/beans.xml");
//获取,不用接口
// UpperLetter changeLetter = (UpperLetter)ac.getBean("changeLetter");
// System.out.println(changeLetter.change());
//使用接口来访问bean
ChangeLetter changeLetter =(ChangeLetter) ac.getBean("changeLetter");
System.out.println(changeLetter.change());
}
}
通过接口的程序,如果要调用LowwerLetter,不需要修改程序,直接修改配置文件,就能达到更改调用的目的。
通过上面的案例,我们可以初步体会到DI配合接口编程,的确可以减少层(web层)和业务层的耦合度
思考题:
接口 ValidateUser
有一个方法 check(??)
有两个类
CheckUser1 implements ValidateUser
{
check //安照xml验证
}
CheckUser2 implements ValidateUser
{
check //到数据库去验证
}
2、装配Bean
2.1 容纳你的bean
bean工厂:最简单的容器,提供了基础的依赖注入支持。创建各种类型的Bean。
应用上下文(ApplicationContext):建立在bean工厂基础之上,提供系统架构服务。
从ApplicationContext应用上下文容器中获取bean和从beanfactory(bean工厂)容器中获取bean
结论,如果使用ApplicationContext,则配置的bean如果是singleton不管你用不用,都会被实例化(好处就是可以预先加载,缺点就是耗内存)
如果是BeanFactory,则当你实例化该对象时候,配置的bean不会被马上实例化,当你使用的时候,才被实例(好处节约内存,缺点就是速度有点慢)
规定:一般没有特殊要求,应当使用ApplicationContext完成(90%)
除了应用上下文提供的附加功能外,应用上下文与bean工厂的另一个重要区别是关于单例bean如何被加载。bean工厂延迟加载所有bean,直到getBean()方法被调用。应用上下文会(applicationContext)在启动后预载入所有单例的bean。这样可确保应用不需要等待他们被创建。
bean的scope细节:singleton,不管是否使用bean,都会创建,否则property,每次使用生成新的bean,还有request、session、global-session三种配置
三种经常用到的实现:
1)ClassPathXmlApplicationContext:从类路径中加载
2)FileSystemXmlApplicationContext:从文件系统中加载
ApplicationContext ac = new FileSystemXmlApplicationContext("D:\\workspace10\\spring1\\src\\com\\cdtax\\ioc\\beans.xml");
3)XmlWebApplicationContext:从web系统加载
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.core.io.ClassPathResource; public class App1 { public static void main(String[] args) { //从ApplicationContext中取bean // ApplicationContext ac = new ClassPathXmlApplicationContext("com/cdtax/ioc/beans.xml"); //当我们去实例化beans.xml,该文件中配置的bean被实例(该bean scope是singleton) //通过文件路径来获取 ApplicationContext ac = new FileSystemXmlApplicationContext("D:\\workspace10\\spring1\\src\\com\\cdtax\\ioc\\beans.xml"); //获取两个student Student s1 = (Student)ac.getBean("student"); Student s2 = (Student)ac.getBean("student"); System.out.println(s1 + " " + s2); //从bean工厂中取出student //如果我们使用beanfactory去获取bean,当你只是实例化该容器,那么 //容器的bean不被实例化,只有当你去使用getBean某个bean时,才会实时的创建bean BeanFactory factory = new XmlBeanFactory(new ClassPathResource("com/cdtax/ioc/beans.xml")); System.out.println("-------------"); factory.getBean("student"); } }
为什么总是一个生命周期当做一个重点?
Servlet->servlet生命周期 init() 的story()
java对象生命周期。
(1)实例化(当我们的程序加载beanx.xml文件),把我们的bean(前提是scope=singleton)实例化到内存,默认使用无参构造函数
(2)调用set方法设置属性
(3)如果实现了BeanNameAware接口(bean名字关注接口),则可以通过setBeanName获取bean的id
(4)如果你实现了bean工厂关注接口(BeanFactoryAware接口),则可以获取BeanFactory。
(5)如果你实现了ApplicationContextAware接口,则调用方法
//该方法传递ApplicationContext
@Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException
{
System.out.println("setApplicationContext" + arg0);
}
(6)如果bean和一个后置处理器关联,则会自动去调用
@Override
public Object postProcessBeforeInitialization(Object arg0, String arg1)
throws BeansException
{
System.out.println("postProcessAfterInitialization 函数被调用");
System.out.println(arg0 + "被创建时间:" + new java.util.Date());
return arg0;
}
(7)如果你实现了InitializingBean接口,则会调用afterPropertiesSet()方法。
(8)若果自己在<bean init-method="init" />则可以在bean中定义自己的初始化方法。
(9)如果bean和一个后置处理器关联,则会自动调用后置处理器的postProcessAfterInitialization方法
(10)使用我们的bean
(11)容器关闭
(12)可以通过实现DisposableBean接口来调用destory方法
(13)可以在<bean id="" destory-method="" />定制自己的销毁方法。
小结:我们实际开发中往往没有用的这么多的过程,常见的是:
1--》2--》6--》9--》10--》11
例子:
package com.cdtax.beanlife; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class PersonService implements BeanNameAware,BeanFactoryAware,ApplicationContextAware, InitializingBean,DisposableBean { private String name; public PersonService() { System.out.println("无参构造函数被调用"); } public String getName() { return name; } public void setName(String name) { System.out.println("setName被调用"); this.name = name; } public void sayHi() { System.out.println("hello " + name); } //该方法arg0表示正在被实例化的bean id @Override public void setBeanName(String arg0) { System.out.println("setBeanName的arg0: " + arg0); } //该方法可以传递beanFactory @Override public void setBeanFactory(BeanFactory arg0) throws BeansException { System.out.println("setBeanFactory :" + arg0); } //该方法传递ApplicationContext @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { System.out.println("setApplicationContext" + arg0); } // @Override public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub System.out.println("afterPropertiesSet 被调用"); } @Override public void destroy() throws Exception { // TODO Auto-generated method stub System.out.println("destroy()被调用"); } public void init() { System.out.println("我自己的init()"); } public void myDestroy() { System.out.println("myDestroy被调用"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="personService" init-method="init" destroy-method="myDestroy" class="com.cdtax.beanlife.PersonService"> <!-- 这里注入我们的属性,前提就是有setName方法才行 --> <property name="name"> <value>小明</value> </property> </bean> <bean id="personService2" class="com.cdtax.beanlife.PersonService"> <!-- 这里注入我们的属性,前提就是有setName方法才行 --> <property name="name"> <value>小明2</value> </property> </bean> <!-- 配置我么会自己的后置处理器(有点类似我们的filter) --> <bean id="myBeanPostProcessor" class="com.cdtax.beanlife.MyBeanPostProcessor"> </bean> </beans>
package com.cdtax.beanlife; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException { System.out.println("postProcessAfterInitialization 函数被调用"); return arg0; } @Override public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException { System.out.println("postProcessBeforeInitialization函数被调用"); System.out.println(arg0 + "被创建时间:" + new java.util.Date()); return arg0; } }
package com.cdtax.beanlife; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App1 { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("com/cdtax/beanlife/beans.xml"); PersonService ps = (PersonService)ac.getBean("personService"); ps.sayHi(); } }
无参构造函数被调用
2014-1-27 11:40:25 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@5fcf29: defining beans [personService,personService2,myBeanPostProcessor]; root of factory hierarchy
setName被调用
setBeanName的arg0: personService
setBeanFactory :org.springframework.beans.factory.support.DefaultListableBeanFactory@5fcf29: defining beans [personService,personService2,myBeanPostProcessor]; root of factory hierarchy
setApplicationContextorg.springframework.context.support.ClassPathXmlApplicationContext@329f3d: display name [org.springframework.context.support.ClassPathXmlApplicationContext@329f3d]; startup date [Mon Jan 27 11:40:25 CST 2014]; root of context hierarchy
postProcessBeforeInitialization函数被调用
com.cdtax.beanlife.PersonService@17431b9被创建时间:Mon Jan 27 11:40:25 CST 2014
afterPropertiesSet 被调用
我自己的init()
postProcessAfterInitialization 函数被调用
无参构造函数被调用
setName被调用
setBeanName的arg0: personService2
setBeanFactory :org.springframework.beans.factory.support.DefaultListableBeanFactory@5fcf29: defining beans [personService,personService2,myBeanPostProcessor]; root of factory hierarchy
setApplicationContextorg.springframework.context.support.ClassPathXmlApplicationContext@329f3d: display name [org.springframework.context.support.ClassPathXmlApplicationContext@329f3d]; startup date [Mon Jan 27 11:40:25 CST 2014]; root of context hierarchy
postProcessBeforeInitialization函数被调用
com.cdtax.beanlife.PersonService@16c9867被创建时间:Mon Jan 27 11:40:25 CST 2014
afterPropertiesSet 被调用
postProcessAfterInitialization 函数被调用
hello 小明