用eclipse安装Spring插件用了好久才搞懂,但是安装的时候又出现问题。所以昨天一天都没更新博客,落下一天的博客记录有点不爽。spring框架估计要搞好久才能上手。还有hibernate没有动手过,所以学完Spring后打算找关于hibernate的项目熟悉一下
天,搞安装弄了一天半,测试成功第一个例子也用了半天,语法逻辑错误不可怕,可怕的是每次学习新的东西出现的那各种五花八门的配置错误。害怕
1.传统方式调用函数
//Dao接口
public interface IUserDao {
//根据用户名和密码查询数据
public void findByUsernameAndPassword();
}
//Service接口
public interface IUserService {
//登录
public void login();
}
//Dao具体实现类
public class UserDaoImpl implements IUserDao{
@Override
public void findByUsernameAndPassword() {
// TODO Auto-generated method stub
System.out.println("UserDaoImpl--Dao层被调用了");
}
}
//Service具体实现类
public class UserServiceImpl implements IUserService{
@Override
public void login() {
// TODO Auto-generated method stub
System.out.println("UserServiceImpl--service层被调用了");
//传统方式调用dao
IUserDao userDao=new UserDaoImpl();
userDao.findByUsernameAndPassword();
}
}
//测试入口类
public class SpringText {
//注解,只允许这一方法(单元测试)
@Test
public void test01d() {
IUserService userService=new UserServiceImpl();
userService.login();
}
}
2.用spring的Ioc和依赖注入
//UserDao接口
package com.igeek;
public interface IUserDao {
//根据用户名和密码查询数据
public void findByUsernameAndPassword();
}
//UserService接口
package com.igeek;
public interface IUserService {
//登录
public void login();
}
//UserDao实现类
package com.igeek;
public class UserDaoImpl implements IUserDao{
@Override
public void findByUsernameAndPassword() {
// TODO Auto-generated method stub
System.out.println("UserDaoImpl--Dao层被调用了");
}
}
//UserService实现类
package com.igeek;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserServiceImpl implements IUserService{
//定义的成员变量必须和配置文件中的name对应
private IUserDao userDao;
//spring框架创建UserServiceImpl对象后,通过setUserDao方法给userDao赋值
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public void login() {
// TODO Auto-generated method stub
System.out.println("UserServiceImpl--service层被调用了");
//传统方式调用dao
//IUserDao userDao=new UserDaoImpl();
//spring的配置方式new对象,IoC控制反转
//读取applicationContex.xml文件,获取bean节点
//ApplicationContext是一个接口,ClassPathXmlApplicationContext是它的一个实现类
// ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
// //获取bean
// IUserDao userDao=(IUserDao) ac.getBean("userDao");
userDao.findByUsernameAndPassword();
}
}
//测试入口类
package com.igeek;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringText {
//注解,只允许这一方法(单元测试)
@Test
public void test01d() {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
IUserService userService=(IUserService) ac.getBean("userService");
//IUserService userService=new UserServiceImpl();
userService.login();
}
}
applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置要创建的对象信息,一个bean对应一个对象 -->
<!-- bean是spring工厂帮你new的一个对象(反射机制) -->
<!-- class是要new的对象的类型的字符串表现形式(一定要全类名) -->
<!-- id/name:标识对象的名字,用来获取bean对象的标识,习惯上,这个名字命名为接口的名字,首字母小写 -->
<bean id="userDao" class="com.igeek.UserDaoImpl"></bean>
<!--
DI(依赖注入) serivice要依赖userDao
双方都必须是bean,在创建service都时候,主动将dao的依赖对象交给service
-->
<bean id="userService" class="com.igeek.UserServiceImpl">
<!--
setter方法注入
name:要与类中的成员变量userDao一致,调用userDao的setUserDao方法
ref:Spring容器中定义的bean对象的名字
-->
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
log4j.properties配置文件
#OFF,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB,ALL
log4j.rootLogger =ALL,systemOut
#\u8F93\u51FA\u5230\u63A7\u5236\u53F0
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout
log4j.appender.systemOut.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.systemOut.Threshold = DEBUG
log4j.appender.systemOut.ImmediateFlush = TRUE
log4j.appender.systemOut.Target = System.err
#\u8F93\u51FA\u5230\u6587\u4EF6
log4j.appender.logFile = org.apache.log4j.FileAppender
log4j.appender.logFile.layout = org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n
log4j.appender.logFile.Threshold = DEBUG
log4j.appender.logFile.ImmediateFlush = TRUE
log4j.appender.logFile.Append = TRUE
log4j.appender.logFile.File = ../Struts2/WebRoot/log/File/log4j_Struts.log
log4j.appender.logFile.Encoding = UTF-8
3.ApplicationContext直译为应用上下文,是用来加载Spring框架配置文件,来构建Spring的工厂对象,它也称之为Spring容器的上下文对象,也称之为Spring的容器。
ApplicationContext只是BeanFactory(Bean工厂,Bean就是一个Java对象)一个子接口
4.为什么不直接使用顶层接口对象来操作呢?
- BeanFactory采取延迟加载,第一次getBean时才会初始化Bean
- BeanFactory的用法:
Beanfactory ac=new XmlBeanFactory(new ClassPathResouse("applicationContext.xml"));
BeanFactory ac =new XmlBeanFactory(new FileSystemResourse("D:\\applicationContext.xl"));
- ApplicationContex是对BeanFactory扩展,提供了更多功能
国际化处理
事件传递
Bean自动装配
各种不同应用层的Contex实现
ApplicationContext更加强大,所以现在开发人员基本没人使用BeanFactory
5.实例化bean的四种方法
//Bean1
package com.igeek;
public class Bean1 {
private String name;
//第一种:通过空的构造方法创建
public Bean1() {
// TODO Auto-generated constructor stub
}
public Bean1(String name) {
this.name = name;
}
}
//Bean2
package com.igeek;
public class Bean2 {
//第二种:静态的构造方法
public static Bean2 getBean2() {
return new Bean2();
}
}
//Bean3
package com.igeek;
public class Bean3 {
}
//Bean3Factory
package com.igeek;
public class Bean3Factory {
public Bean3 getBean3() {
return new Bean3();
}
}
//Bean4
package com.igeek;
public class Bean4 {
}
//FactoryBean
package com.igeek;
import org.springframework.beans.factory.FactoryBean;
public class Bean4FactoryBean implements FactoryBean<Bean4>{
@Override
public Bean4 getObject() throws Exception {
// TODO Auto-generated method stub
//可以写一些初始化数据、连接等代码
return new Bean4();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return null;
}
}
//测试类
package com.igeek;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringTest {
@Test
public void test1() {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Bean1 bean1=(Bean1) ac.getBean("bean1");
System.out.println(bean1);
}
@Test
public void test2() {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Bean2 bean2=(Bean2) ac.getBean("bean2");
System.out.println(bean2);
}
@Test
public void test3() {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Bean3 bean3=(Bean3) ac.getBean("bean3");
System.out.println(bean3);
}
@Test
public void test4() {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
Bean4 bean4=(Bean4) ac.getBean("bean4");
System.out.println(bean4);
}
}
//applicationContext.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:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 第一种:用空的构造方法 最常用-->
<bean id="bean1" class="com.igeek.Bean1"></bean>
<!--
第二种:静态工厂创建bean 框架初始化用得比较多
用来自定义工厂,让spring的工厂来调用自定义的工厂,可以将对象的创建权限交给自定义的工厂
-->
<bean id="bean2" class="com.igeek.Bean2" factory-method="getBean2"></bean>
<!-- 第三种:实例工厂的方式实例化bean,bean3Factory是实例化工厂 框架初始化用得比较多 -->
<bean id="bean3Factory" class="com.igeek.Bean3Factory"></bean>
<!-- factory-bean 相当于ref,引用一个bean对象 -->
<bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3"></bean>
<!--
第四种:实现接口FactoryBean(spring框架底层用得比较多
Spring在准备实例化bean的时候,new Bean4FactoryBean,没有急着返回bean对象
会判断,类型对象是否实现了FactoryBean接口,如果实现了,就调用接口的getObject()方法
得到bean实例,返回bean对象
-->
<bean id="bean4" class="com.igeek.Bean4FactoryBean" ></bean>
<!-- beanFactory和FactoryBean的区别:
beanFactory是找配置文件的顶层接口
FactoryBean是bean的生成工具,获取bean
-->
</beans>
6.bean的作用域
Spring 框架支持以下五个作用域,分别为singleton、prototype、request、session和global session,5种作用域说明如下所示,
注意,如果你使用 web-aware ApplicationContext 时,其中三个是可用的。
作用域 | 描述 |
---|---|
singleton | 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境 |
global-session | 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境 |
singleton 作用域:
singleton 是默认的作用域,也就是说,当定义 Bean 时,如果没有指定作用域配置项,则 Bean 的作用域被默认为 singleton。
当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。
也就是说,当将一个bean定义设置为singleton作用域的时候,Spring IoC容器只会创建该bean定义的唯一实例。
Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。
prototype 作用域
当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
//SingletonBean
package com.igeek.scope;
public class SingletonBean {
public SingletonBean() {
// TODO Auto-generated constructor stub
System.out.println("SingletonBean:初始化");
}
}
//PrototypeBean
package com.igeek.scope;
public class PrototypeBean {
public PrototypeBean() {
// TODO Auto-generated constructor stub
System.out.println("PrototypeBean:初始化");
}
}
//测试类
package com.igeek;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.igeek.scope.PrototypeBean;
import com.igeek.scope.SingletonBean;
public class SpringTest1 {
@Test
public void testScope() {
//1,先构建实例化获取spring容器
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//2,看看多次获取bean的时候是不是同一个
//单例模式:节省内存开销(只初始化一次)
SingletonBean singletonBean1=(SingletonBean) ac.getBean("singletonBean");
SingletonBean singletonBean2=(SingletonBean) ac.getBean("singletonBean");
System.out.println(singletonBean1);
System.out.println(singletonBean2);
//多例模式:(初始化两次)
PrototypeBean prototypeBean1=(PrototypeBean) ac.getBean("prototypeBean");
PrototypeBean prototypeBean2=(PrototypeBean) ac.getBean("prototypeBean");
System.out.println(prototypeBean1);
System.out.println(prototypeBean2);
}
}
//applicationContext.xml里增加
<!-- bean的作用域 -->
<!-- spring默认单例scope="singleton" ,可以不用配置-->
<bean id="singletonBean" class="com.igeek.scope.SingletonBean" scope="singleton"></bean>
<bean id="prototypeBean" class="com.igeek.scope.PrototypeBean" scope="prototype"></bean>
7.Bean的生命周期
Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
通过init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。
通过destroy-method 指定一个方法,销毁对象前调用该方法。
关于数据(一些属性等等)的初始化
- 直接赋值
- 在构造器中初始化
- 使用单独的初始化方法
//bean对象
package com.igeek.xmllifecycle;
public class LifeCycleBean {
//三种初始化方式
//1.初始化成员变量
private String name="tom";//初始化成员变量
public LifeCycleBean() {
// TODO Auto-generated constructor stub
System.out.println("LifeCycleBean 构造器被调用了");
//2.通过构造方法初始化
this.name="herl";
}
//构造方法调用后执行此方法,需要在xml中配置后才能生效
public void init() {
System.out.println("LifeCycleBean 构造器调用后执行");
//3.单独的初始化方法来初始化数据
this.name="feng";
}
//业务方法
public void save() {
System.out.println("执行了业务save方法");
}
//bean销毁前调用的方法
public void destroy() {
System.out.println("LifeCycleBean -destroy销毁前调用");
System.out.println(name);
}
}
//测试类
package com.igeek.xmllifecycle;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class SpringText {
@Test
public void testCycle() {
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
LifeCycleBean lifeCycleBean=(LifeCycleBean) ac.getBean("lifeCycleBean");
lifeCycleBean.save();
//为什么没有销毁方法调用?
//原因:使用debug模式,jvm直接就关了,spring容器还没有来得及销毁对象,所以看不到
//解决:可以手动销毁spring容器,只能销毁单例的对象
((ClassPathXmlApplicationContext)ac).close();
}
}
//applicationContext.xml中增加
<!-- bean的生命周期 -->
<bean id="lifeCycleBean" class="com.igeek.xmllifecycle.LifeCycleBean"
init-method="init" destroy-method="destroy" scope="singleton"
></bean>
8.后处理bean
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
BeanPostProcessor 接口定义回调方法,你可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等。你也可以在 Spring 容器通过插入一个或多个 BeanPostProcessor 的实现来完成实例化,配置和初始化一个bean之后实现一些自定义逻辑回调方法。
//在7.的基础上增加类
package com.igeek.xmllifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor{
//初始化之后调用
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if(beanName.equals("lifeCycleBean")) {
System.out.println(beanName+"在初始化之后增强");
}
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
//初始化之前调用 bean:返回的bean;beanName:bean的名称
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
if(beanName.equals("lifeCycleBean")) {
System.out.println(beanName+"在初始化之前增强");
}
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
}
//applicationContext.xml中增加
<!-- 后处理bean -->
<bean class="com.igeek.xmllifecycle.MyBeanPostProcessor"></bean>