Spring -- 入门,装备集合,自动装配,分散装配,自定义编辑器
1. 概要
struts2:web hibernate:持久化 spring:业务层.管理bean的,容器.List Map Set. 体验spring: 1.创建java项目. 2.引入spring的类库. ${spring解压目录}/dist/spring.jar ${spring解压目录}/lib/jakarta-commons/commons-logging.jar 2'.创建业务类. /** * GreetingService */ public class GreetingService { private String greeting ;//get/set private String greeting2 ;//get/set /* byeService */ private ByeService bs ;//get/set public void sayGreeting(){ bs.sayBye(); } } /** * ByeService */ public class ByeService { private String bye ; public String getBye() { return bye; } public void setBye(String bye) { this.bye = bye; } public void sayBye(){ System.out.println(bye); } } 3.配置spring的配置文件.src/applicationContext.xml schema:${spring解压目录}\docs\reference\html_single\index.html\3.2.1.1 <?xml version="1.0"?> <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-2.5.xsd"> <!-- 欢迎服务 --> <bean id="greetingService" class="cn.itcast.spring.service.GreetingService"> <property name="greeting"> <value>hello world</value> </property> <property name="greeting2" value="tom" /> <property name="bs" ref="byeService" /> </bean> <!-- 欢送服务 --> <bean id="byeService" class="cn.itcast.spring.service.ByeService"> <property name="bye"> <value>later</value> </property> </bean> </beans> 4.创建app. ApplicationContext ac = new ClassPathXmlApplicationContext( "applicationContext.xml"); GreetingService gs = (GreetingService) ac.getBean("greetingService"); gs.sayGreeting(); gs.sayGreeting2(); ByeService bs = (ByeService) ac.getBean("byeService"); bs.sayBye(); spring: ioc: inverse of control,反转控制.获得依赖对象的方式被反转了. (不要手动new bean对象) 1.new.(spring负责对象实例化) 2.组装对象的出发点是反的(相对于bean的依赖关系是反的). DI:dependency injection,依赖注入. <==> ioc aop: aspect oriented program,面向方面编程. oop:面向对象编程. soa: GreetingService gs = new ...(); gs.setByeService(bs); ByeService bs = new ...(); gs.sayGreeting(); BeanFactory:实例化bf时,不会实例化任何bean,只有getBean的时候,才实例化相关的bean.节省资源. ApplicationContext:实例化ac时,实例化单例bean. 懒汉式: public class A{ private A(){} public static A instance = null ; public static A getInstance(){ if(instance == null){ instance = new A(); } return instance ; } } 饿汉式: public static A instance = new A(); spring单利bean,对应的bean的叫做prototype(原型bean). ac.getBean("bs"); == new ByeService(); 生命周期: 1.new 2.set DI 3.BeanNameAware:bean名关注 4.BeanFactoryAware:bean工厂关注 5.BeanPostProcessor.beforeInitialization(); 5'.调用InitializingBean.afterPropertySet()方法. 6.init-method 7.BeanPostProcessor.afterInitialization(); spring()框架. 代码的入侵. 1.高侵入性 2.低侵入 3.非侵入行 jee:jsp servlet jpa jta ejb(enterprise javabean),jndi pojo:plain old java object. BeanDefinition:bean的定义,spring对bean的信息的封装. Root bean: class [cn.itcast.spring.service.GreetingService]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=ini; destroyMethodName=release; defined in class path resource [applicationContext.xml] Class clazz = Class.forName("cn.itcast.spring.service.GreetingService"); clazz.newInstance(); scope:prototype singleton request session global_session <struts> <package namepace extends=""> 在ide下注册spring中的schema文件. ${spring解压目录}\dist\resources\*.xsd. List Set Map: Properies: .properties <hibernate-mapping> <class name table lazy> <id > <generator class="" /> </id> <property name="age" column access="field"> </class> spring通过构造函数参数注入依赖强化依赖关系. 自动装配: 1.byName:按照名称自动装配,寻找和bean的属性名相一致的bean的id.(bean必须有空的构造,通过set方法注入) 2.byType:按照属性的类型来自动装配,如果找到多个,抛异常.(bean必须有空的构造,通过set方法注入) 3.constructor:按照构造函数参数的类型自动装配,如果找不到或者找多个,都抛异常. 4.autodetact:自动检测,在(2)和(3)之间选择一个 5.no. 6.default,跟<beans default-autowire属性>保持一致. 分散配置: 把需要在上下文硬编码的属性拿到外部的属性文件中定义,让上下文从外部文件提取值. 自定义编辑器: 将字符串转换成相应的对象,
2. Spring中bean的生命周期, 及其工作流程
bean被载入到容器中时,他的生命周期就开始了。bean工厂在一个bean可以使用前完成很多工作:
1).容器寻找bean的定义信息并实例化。
2).使用依赖注入,spring按bean定义信息配置bean的所有属性。
3).若bean实现了BeanNameAware接口,工厂调用Bean的setBeanName()方法传递bean的ID。
4).若bean实现了BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
5).若BeanPostProcessor和bean关联,则它们的postProcessBeforeInitialization()方法被调用。
6).若bean指定了ini-method方法、,它将被调用。
7).最后,若有BeanPostProcessor和bean关联,则它们的postProcessAfterInitialization()方法被调用、。
示例代码一: BeanPostProcessor 注册bean后处理器,能给所有bean做初始和收尾工作,等效于在xml文件中配置init-method="ini" destroy-method="release"。
如果bean构造时 需要调用有参的构造函数,可以在constructor-arg 中配置。
ByeService.java , javabean
public class ByeService { private String bye ; public String getBye() { return bye; } public void setBye(String bye) { this.bye = bye; } public void sayBye(){ System.out.println(bye); } }
GreetingService.java, javabean
public class GreetingService implements BeanNameAware,BeanFactoryAware{ private String greeting ; private String greeting2 ; /* byeService */ private ByeService bs ; public GreetingService(ByeService bs){ this.bs = bs ; System.out.println("Constructor: new GreetingService()"); } public GreetingService(String str1,String str2){ System.out.println("1111"); } public GreetingService(String str1,Integer str2){ System.out.println("2222"); } public GreetingService(String str1,int str2){ System.out.println("3333"); } public GreetingService(int str1,String str2){ System.out.println("4444"); } /** * beannameAware,注入bean的id */ public void setBeanName(String name) { System.out.println("BeanNameAware:setBeanName() : " + name); } /** * bean工厂关注 */ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryAware:setBeanFactory() : " + beanFactory); } public ByeService getBs() { return bs; } public void setBs(ByeService bs) { this.bs = bs; System.out.println("DI:setBs() : " + bs); } public String getGreeting() { return greeting; } public void setGreeting(String greeting) { this.greeting = greeting; System.out.println("DI:setGreeting() : " + greeting); } public void sayGreeting(){ bs.sayBye(); } public void sayGreeting2(){ System.out.println(greeting2); } public String getGreeting2() { return greeting2; } public void setGreeting2(String greeting2) { this.greeting2 = greeting2; System.out.println("DI:setGreeting2() : " + greeting2); } /** * 定制初始化方法 */ public void ini(){ System.out.println("ini"); } /** * 定制销毁方法 */ public void release(){ System.out.println("release"); } }
MyBeanPostProcessor.java, bean的后处理器
public class MyBeanPostProcessor implements BeanPostProcessor { /** * 后处理 */ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeanPostProcessor:after:" + beanName); return bean; } /** * 之前处理 */ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeanPostProcessor:before:"+beanName); return bean; } }
applicationContext.xml 配置文件
<?xml version="1.0"?> <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-2.5.xsd"> <!-- 欢迎服务 --> <bean id="greetingService" class="cn.itcast.spring.service.GreetingService" scope="singleton" init-method="ini" destroy-method="release"> <constructor-arg index="1" type="java.lang.String" value="12" /> <constructor-arg index="0" type="int" value="24" /> <property name="greeting"> <value>hello world</value> </property> <property name="greeting2" value="tom" /> <property name="bs" ref="byeService" /> </bean> <!-- 欢送服务 --> <bean id="byeService" class="cn.itcast.spring.service.ByeService"> <property name="bye"> <value>later</value> </property> </bean> <!-- 注册bean后处理器 --> <bean id="myBeanPostProcessor" class="cn.itcast.spring.beanprocessor.MyBeanPostProcessor" /> </beans>
App.java
public class App { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext( "applicationContext.xml");//src下 不需要加全路径 GreetingService gs = (GreetingService) ac.getBean("greetingService"); gs.sayGreeting(); gs.sayGreeting2(); ByeService bs = (ByeService) ac.getBean("byeService"); bs.sayBye(); ((ClassPathXmlApplicationContext)ac).destroy(); } }
3. 集合装配bean
单例和原型模式: prototype、singleton、request session、global-session ,spring中的bean缺省情况下是单例模式。始终返回一个实例。若想返回不同的实例的话需要定义成原型模式。bean的singleton属性告诉上下文该bean是否为单例的。缺省为true。若为false的话,为原型bean。
<bean id="foo" class="...Foo" singleton="false"/>
<!– spring2.5 -->
<bean scope="prototype|single|..">
<bean id="foo" class="...Foo" autowire="autowire type">
有四种自动装配类型:
1.byName:寻找和属性名相同的bean,若找不到,则装不上。
2.byType:寻找和属性类型相同的bean,找不到,装不上,找到多个抛异常。
3.constructor:查找和bean的构造参数一致的一个或多个bean,若找不到或找到多个,抛异常。按照参数的类型装配
4.autodetect:(3)和(2)之间选一个方式。不确定性的处理与(3)和(2)一致。(选择标准:是否有含参的构造函数,没有则是byType)
<bean id="bar" class="Bar" autowire="byName"/>
<!-- spring2.5 -->
@Autowired
<bean class="... AutowiredAnnotationBeanPostProcessor">
示例代码二: (通过util定义集合bean需要手动添加 spring-util-2.5.xsd)
PopSet.java, javabean
public class PopSet { private String[] ss ; private List list ; private Set set ; private Map map ; private Properties prop ; .....省略 get set方法 }
popSet.xml 配置文件, java bean中的 prop 对应到配置文件中用标签<prop> </prop>配置。
<?xml version="1.0"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:util="http://www.springframework.org/schema/util" 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-2.5.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd "> <bean id="popSet" class="cn.itcast.spring.popset.PopSet"> <property name="ss"> <list> <value>1</value> <value>tom</value> </list> </property> <property name="list" ref="myList" /> <property name="set"> <set> <value>1</value> <value>tom</value> <ref bean="byeService"/> <ref bean="byeService"/> <bean class="cn.itcast.spring.service.ByeService"> <property name="bye" value="kk" /> </bean> <bean class="cn.itcast.spring.service.ByeService"> <property name="bye" value="kk" /> </bean> </set> </property> <property name="map"> <map> <entry key="key001" value="tom" /> <entry key="key002" value-ref="byeService" /> <entry key="key003"> <bean class="cn.itcast.spring.service.ByeService" /> </entry> </map> </property> <property name="prop"> <props> <prop key="key001">tom</prop> <prop key="key002">tom1</prop> <prop key="key003">tom2</prop> </props> </property> </bean> <bean id="byeService" class="cn.itcast.spring.service.ByeService"> <property name="bye" value="over" /> </bean> <!-- 通过util定义集合bean --> <util:list id="myList"> <value>1</value> <value>2</value> <value>tom</value> <ref bean="byeService"/> <ref bean="byeService"/> <bean class="cn.itcast.spring.service.ByeService"> <property name="bye" value="kk" /> </bean> <bean class="cn.itcast.spring.service.ByeService"> <property name="bye" value="kk" /> </bean> </util:list> </beans>
App.java
public class App { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext( "cn/itcast/spring/popset/popSet.xml"); ac.getBean("popSet"); } }
4.分散装配
将配置文件分成几个分散的配置文件。如配置数据库的 jdbc.properties文件。使用占位符变量代替bean装配文件中的硬编码配置。占位符采${variable}形式。
定制属性编辑器 , 如下利用自定义的编辑器能将 省市县装配到homeAddress对应的属性中去。
<property name="homeAddress">
<value>湖南省.长沙市.宁乡县.花明楼镇</value>
</property>
示例代码三:
Address.java, javabean
public class Address { private String province; private String city; private String street; private String zipCode; ......省略 set get方法 }
Scatter.java, javabean
public class Scatter { private String driverClass ; private String url ; private String username ; private String password ; private Address comAddress ;//公司地址 private Address homeAddress ;//家庭地址 }
jdbc.properties 分散配置的 prop文件
jdbc.driverclass=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/test jdbc.username=root jdbc.password=root
AddressEditor.java 自定义编辑器
public class AddressEditor extends PropertyEditorSupport { public void setAsText(String text) throws IllegalArgumentException { if(text != null && text.length() > 0){ String[] ss = text.split("\\."); if(ss != null && ss.length > 3){ Address a = new Address(); a.setProvince(ss[0]); a.setCity(ss[1]); a.setStreet(ss[2]); a.setZipCode(ss[3]); //将转换成的地址对象设置给相应的属性上 setValue(a); } else{ setValue(null); } } else{ setValue(null); } } }
scatter.xml 配置文件
<?xml version="1.0"?> <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" 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 "> <!-- 分散配置(属性占位符配置器) <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:cn/itcast/spring/scatter/jdbc.properties</value> </list> </property> </bean> --> <!-- 自定义编辑器配置器 --> <bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <!-- 自定义编辑器集 --> <property name="customEditors"> <map> <entry key="cn.itcast.spring.scatter.Address"> <bean class="cn.itcast.spring.editor.AddressEditor" /> </entry> </map> </property> </bean> <bean id="scatter" class="cn.itcast.spring.scatter.Scatter"> <property name="driverClass" value="${jdbc.driverclass}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!-- --> <property name="comAddress"> <bean class="cn.itcast.spring.scatter.Address"> <property name="province" value="jilin" /> <property name="city" value="cc" /> <property name="street" value="${jdbc.url}" /> </bean> </property> <property name="homeAddress"> <value>${jdbc.driverclass}.cc.renmin.139988</value> </property> </bean> <!-- 分散配置,加载分散配置的文件 --> <context:property-placeholder location="classpath:cn/itcast/spring/scatter/jdbc.properties"/> </beans>
App.java
public class App { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext( "cn/itcast/spring/scatter/scatter.xml"); ac.getBean("scatter"); } }