2、srping进阶

spring开发提倡接口编程,配合DI技术可以达到层与层间的解耦

1、体验spring的DI配合接口编程,完成一个字母大小写转换的案例:

思路:

1)创建一个接口ChangeLetter

package com.cdtax.inter;

public interface ChangeLetter
{
	//声明一个方法
	public String change();
}

2)两个类实现接口

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();
	}

}

3)把对象配置到spring容器中,位置为com.cdtax.inter,名字为beans.xml

<?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());
	}
}

4)通过更改配置文件,修改调用的对象

通过接口的程序,如果要调用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");
	}
}

3、bean的生命周期

为什么总是一个生命周期当做一个重点?

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 小明

你可能感兴趣的:(2、srping进阶)