Spring的初体验
)
什么是Spring
Spring是一个开源的**控制反转(Inversion of Control,IOC)和面向切面(Aspect Oriented Programming,AOP)**的容器框架,它的主要目的是简化企业开发。
IOC控制反转
什么是控制反转:Inversion of Control 就是应用本身不负责依赖对象的创建和维护,依赖对象的创建和维护由外部容器负责。这样控制权就由应用转移到外部容器,控制权的转移就是所谓的反转。
public class PersonbizImple {
private PersonDao personDao;
public void save(Person person){
personDao.save(person);
}
}
PersonDaoBean 是在应用内部创建及维护的。
依赖注入(Dependency Injection)
biz中目前定义的只是dao的接口,那么外部容器创建完毕之后就要传递进来(构造方法,set),但是并不是人工传递调用,而是运行时动态的注入进来。
当我们把依赖对象交给外部容器负责创建,那么PersonServiceBean 类可以改成如下:
public class PersonbizImpl {
private PersonDao personDao ;
//通过构造器参数,让容器把创建好的依赖对象注入进PersonServiceBean,当然也可以使用setter方法进行注入。
public PersonbizImpl(PersonDao personDao){
this.personDao=personDao;
}
public void save(Person person){
personDao.save(person);
}
}
所谓依赖注入就是指:在运行期,由外部容器动态地将依赖对象注入到组件中。
为何要使用Spring
在项目中引入spring立即可以带来下面的好处:
- 降低组件之间的耦合度,实现软件各层之间的解耦。(只要知道接口不需要知道实现类)
- 可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务.也不需处理复杂的事务传播。
(不需要知道什么时候事务begin,什么时候失败需要回滚) - 容器提供单例模式支持,开发人员不再需要自己编写实现代码。
- 容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
- 容器提供的众多辅作类,使用这些类能够加快应用的开发,如: JdbcTemplate、 HibernateTemplate。
- Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样更便于应用的开发。
轻量级与重量级概念的划分
经常会有同学问到spring属于轻量级框架,还是重量框架?其实划分一个应用是否属于轻量级还是重量级,主要看它使用了多少服务.使用的服务越多,容器要为普通java对象做的工作就越多,必然会影响到应用的发布时间或者是运行性能.
对于spring容器,它提供了很多服务,但这些服务并不是默认为应用打开的,应用需要某种服务,还需要指明使用该服务,如果应用使用的服务很少,如:只使用了spring核心服务,那么我们可以认为此时应用属于轻量级的,如果应用使用了spring提供的大部分服务,这时应用就属于重量级
如何实例化spring容器
实例化Spring容器常用的两种方式:
方法一:
在类路径下寻找配置文件来实例化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
方法二:
在文件系统路径下寻找配置文件来实例化容器
ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{“d:\\beans.xml“});
Spring的配置文件可以指定多个,可以通过String数组传入。
从spring容器中得到bean
当spring容器启动后,因为spring容器可以管理bean对象的创建,销毁等生命周期,所以我们只需从容器直接获取Bean对象就行,而不用编写一句代码来创建bean对象。从容器获取bean对象的代码如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext(“beans.xml”);
OrderService service = (OrderService)ctx.getBean("personService");
三种实例化bean的方式
1.使用类构造器实例化
<bean id=“orderService” class=“cn.itcast.OrderServiceBean”/>
实例化无参构造函数
2.使用静态工厂方法实例化
<bean id="personService" class="cn.itcast.service.OrderFactory" factory-method="createOrder"/>
public class OrderFactory {
public static OrderServiceBean createOrder(){
return new OrderServiceBean();
}
}
3.使用实例工厂方法实例化:
<bean id="personServiceFactory" class="cn.itcast.service.OrderFactory"/>
<bean id="personService" factory-bean="personServiceFactory" factory-method="createOrder"/>
public class OrderFactory {
public OrderServiceBean createOrder(){
return new OrderServiceBean();
}
}
Bean的作用域
singleton 单例模式
在每个Spring IoC容器中一个bean定义只有一个对象实例。默认情况下会在容器启动时初始化bean,但我们可以指定Bean节点的lazy-init=“true”来延迟初始化bean,这时候,只有第一次获取bean会才初始化bean。如:
<bean id="xxx" class="cn.itcast.OrderServiceBean" lazy-init="true"/>
如果想对所有bean都应用延迟初始化,可以在根节点beans设置default-lazy-init=“true“,如下:
<beans default-lazy-init="true“ ...>
.prototype
每次从容器获取bean都是新的对象。
.request
.session
.global session
.request
表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效
.session
表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效
.globalSession
不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session
的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。
以上3种均基于web的Spring ApplicationContext(WEB项目)情形下有效
Bean的初始化方法和销毁方法
<bean id="xxx" class=“biz.OrderServiceBean" init-method="init" destroy-method="close"/>
public void init() {
System.out.println(“已经初始化了”);
}
public void close() {
System.out.println(“被销毁了”);
}
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
PersonService person = (PersonService)ctx.getBean("personServiceBean");
ctx.close();
注意:必须是无参的方法,可以有返回值。
注入依赖对象
基本类型对象注入:
<bean id="orderService" class="cn.itcast.service.OrderServiceBean">
<constructor-arg index=“0” type=“java.lang.String” value=“xxx”/>//构造器注入
<property name=“name” value=“zhao/>//属性setter方法注入
</bean>
注入其他bean:表示null值
方式一
<bean id="orderDao" class="cn.itcast.service.OrderDaoBean"/>
<bean id="orderService" class="cn.itcast.service.OrderServiceBean">
<property name="orderDao" ref="orderDao"/>
</bean>
方式二(使用内部bean,但该bean不能被其他bean引用) 不推荐使用
<bean id="orderService" class="cn.itcast.service.OrderServiceBean">
<property name="orderDao">
<!--没有id(name)属性,所以不能被其它引用-->
<bean class=“cn.itcast.service.OrderDaoBean”/>
</property>
</bean>
注入依赖对象之集合类型的装配
public class OrderServiceBean {
private Set<String> sets = new HashSet<String>();
private List<String> lists = new ArrayList<String>();
private Properties properties = new Properties();
private Map<String, String> maps =
new HashMap<String, String>();
....//这里省略属性的getter和setter方法
}
<bean id="order" class="cn.itcast.service.OrderServiceBean">
<property name="lists">
<list>
<value>pkbest</value>
</list>
</property>
<property name="sets">
<set>
<value>pkbest</value>
</set>
</property>
<property name="maps">
<map>
<entry key=“pkbest" value="28"/>
</map>
</property>
<property name="properties">
<props>
<prop key=“pk">best</prop>
</props>
</property>
</bean>
依赖注入的常用方法
1. 使用构造器注入
2. 使用属性setter方法注入
3. 使用Field注入
(用于注解方式,只需要定义属性,不需要get,set但是需要用注解,叫做自动装配)
依赖注入----手工装配
方法1. 在xml配置文件中,通过在bean节点下配置,如
<bean id="orderService" class="cn.itcast.service.OrderServiceBean">
<constructor-arg index=“0” type=“java.lang.String” value=“xxx”/>//构造器注入
<property name=“name” value=“zhao/>//属性setter方法注入
</bean>
方法2:在java代码中使用@Autowired或@Resource注解方式进行装配,这两个注解的区别是:@Autowired 默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@Autowired
private PersonDao personDao;//用于字段上
@Autowired
public void setOrderDao(OrderDao orderDao) {//用于setter方法上
this.orderDao = orderDao;
}
@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在
@Resource注解和@Autowired一样,也可以标注在字段或setter方法上,但它默认按名称装配。名称可以通过@Resource的name属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在setter方法上,即默认取bean名称寻找依赖对象。
@Resource(name=“personDaoBean”)
private PersonDao personDao;//用于字段上
注意:如果没有指定name属性,并且按照默认的名称找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。
通过在classpath自动扫描方式把组件纳入spring容器中管理
前面的例子我们都是使用XML的bean定义来配置组件。在一个稍大的项目中,通常会有上百个组件,如果这些这组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。spring为我们引入了组件自动扫描机制,他可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进spring容器中管理。它的作用和在xml文件中使用bean节点配置组件是一样的。要使用自动扫描机制,我们需要打开以下配置信息:
<context:component-scan base-package=“cn.itcast”/>
其中base-package为需要扫描的包(含子包)。
@Service用于标注业务层组件(biz.impl)、 @Controller用于标注控制层组件(如struts中的action)、@Repository用于标注数据访问组件,即DAO组件。而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上) @PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)