[SPRING]Spring学习笔记之二----Spring中的Bean

194 阅读8分钟

什么是Spring中的Bean???

Bean实际上是一个普通的java类,普通java类配置到spring的配置文件中,通过容器来生成对象,生成出来的对象就叫做Bean。如果把Sping看做一个大型工厂,则Spring容器中的Bean就是该工厂的产品。要想使用这个工厂生产或管理Bean,就需要在配置文件中告诉他需要哪些Bean,以及需要使用何种方式将这些Bean装配到一起。

Bean的配置

Spring中的XML配置文件的根元素是< beans >,< beans >中包含 了多个< bean>子元素,每一个< bean >子元素定义了一个Bean,并捲述了该Bean如何被装配到Spring容器中。关于< beans >元素的常用属性如下表所示:

Bean的实例化

Bean的实例化有哪些方式?

在面向对象的程序中,要想使用某个对象,就需要先实例化这个对象。同样,在Spring中,要想使用容器中的Bean,也需要实例化Bean。实例化Bean有三种方式:构造器实例化,静态工厂方式实例化和实例化工厂方式实例化(其中最常用的是构造器实例化)

构造器实例化

构造器实例化是指Spring容器通过Bean(普通java类)对应的类中默认的构造函数(无参构造函数)来实例化Bean。接下来演示一下构造器实例化:

1、创建一个普通java类

    //使用类中默认的无参构造方法
    public class Bean1 {}

2、编写配置文件

    //id为唯一标识符,class表示的是bean的全限定名,表明bean所在的位置
    <bean id="bean1" class="com.mq.contructor.Bean1"></bean>

3、测试

在main方法中执行,若能打印出实例化bean的地址,则成功实例化bean
    	//定义配置文件路径
	String xmlPath="com/mq/contructor/Bean1.xml";
	//ApplicationContext 在加载配置文件时,对Bean进行实例化
	ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
	Bean1 bean=(Bean1)applicationContext.getBean("bean1");
	System.out.println(bean);

静态工厂实例化

静态工厂是实例化Bean的另一种方法。该方法要求自己创建一个静态工厂的方法来创建Bean的实例。

1、创建一个普通java类

	public class Bean2 {}

2、创建一个工厂,并且一定要有一个静态的方法

public class MyBean2Factory {
    	public static Bean2 createBean() {
			return new Bean2();
		}
	}

3、编写spring配置文件(class写静态工厂的全限定名)

    //factory-method的值为具体的方法名称    
    <bean id="bean2" class="com.mq.factory.MyBean2Factory" 
    factory-method="createBean"></bean>

4、编写测试类

同样能成功打印出实例化bean的地址
	//定义配置文件的路径
	//ApplicationContext在加载配置文件,对Bean进行实例化
	ApplicationContext applicationContext=new ClassPathXmlApplicationContext("com/mq/factory/Bean1.xml");
	System.out.println(applicationContext.getBean("bean2"));

实例工厂方法实例化

实例工厂是采用直接创建Bean实例的方式,在配置文件中,通过factory-bean属性来配置一个实例工厂,然后通过factory-method属性确定使用工厂中的哪个方法。

1、创建普通java类

2、创建一个工厂,并且为无参构造函数加入一条打印语句,输出则证明MyBean3Factory被实例化

    public class MybBean3Factory {
	public MybBean3Factory() {
		System.out.println("Bean3工厂实例化!");
            }
	public Bean3 createBean() {
		return new Bean3();
	    }
	}

3、编写测试类

//指定配置文件路径
String xmlPath="com/mq/factory1/Bean3.xml";
//ApplicationContext加载配置文件时,对Bean进行实例化
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath);
System.out.println(applicationContext.getBean("bean3"));

Bean3对象被成功实例化,并且打印出无参构造方法中的的输出语句。

Bean的作用域

在Spring中,bean作用域用于确定哪种类型的bean实例应该从Spring容器中返回给调用者。Spring中为Bean的实例定义了7种作用域,如下所示

1、singleton作用域

Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。 singleton是Spring容器默认的作用域,当Bean的作用域为singleton时,Spring容器就只会在一个共享的Bean实例。singleton作用域对于无会话状态的Bean(Dao组件,Service组件)来说是最理想的选择。

在配置文件中,配置scope属性为singleton

<bean id="scope" class="com.mq.scope.Scope" scope="singleton"></bean>

在测试类中进行测试:

    // 定义配置文件路径
    String classPath = "com/mq/scope/Bean4.xml";
    // 加载配置文件
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext(classPath);
    // 输出获得的实例
    System.out.println(applicationContext.getBean("scope"));
    System.out.println(applicationContext.getBean("scope"));
    System.out.println(applicationContext.getBean("scope"));
    System.out.println(applicationContext.getBean("scope"));

接下来通过getBean()方法获取多个实例对象,都只获取同一个实例对象,运行结果如下:

prototype作用域

prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。 在需要保持会话状态的Bean(如Struts2的Action类)应该使用prototype作用域。在使用prototype作用域是,Spring容器回为每个对该Bean的请求都创建一个新的实例。 修改配置文件的scope属性为prototype:

<bean id="scope" class="com.mq.scope.Scope" scope="prototype"></bean>

再运行测试类,结果如下:

每次获取的实例都是新创建的实例!!!

Bean的生命周期

了解Spring中Bean的生命周期的意义就在于,可以利用Bean在其 存活期间的特定时刻完成一些相关操作。这种时刻可能有很多,但一 般情况下,常会在Bean的postinitiation(初始化后)和predestruction(销 毁前)执行一些相关操作。例如初始化后要传一些初始化参数,销毁前要关闭一些找资源

Spring容器中Bean的生命周期流程如下图所示:

为了更好的演示Bean的生命周期,通过一个小案例来进行演示: 1、在普通java类中自定义构造方法、初始化方法和销毁方法

public class life {
    //构造方法,也是实例化
    public life() {
    	System.out.println("life START!!");
    }
    //初始化方法
    public void initMethod() {
    	System.out.println("initMethod START!!!");
    }
    //销毁方法
    public void destroyMethod() {
    	System.out.println("destroyMethod START!!!!");
    }
}

2、在配置文件中做如下配置,配置自定义的初始化方法和销毁方法:

<!-- scope="singleton" 默认为ingleton作用域,这种情况下spring能够全程跟踪bean的生命周期 -->
<bean id="life" class="com.mq.life.life" init-method="initMethod" destroy-method="destroyMethod"></bean>

3、编写测试类进行测试

    //定义配置文件路径
    String xmlPath="com/mq/life/life.xml";
    //classPathXmlApplication 在加载配置文件时,对Bean进行实例化
    ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext(xmlPath);
    //ClassPathXmlApplicationContext 提供了关闭容器的方法,这样Bean的销毁方法才会被调用
    context.close();

运行结果如下:

可见分别调用了自定义的构造方法,初始化方法和销毁方法。

什么时Bean的装配??

Bean的装配可以理解为依赖关系注入,Bean的装配方式即Bean依赖注入的方式。spring容器支持多种形式的Bean的装配方式,如基于XML的装配、基于注解(Annotation)的装配和自动装配(其中最常用的是基于注解的装配)。

基于Annotation的装配(注解)

基于XML的装配可能会导致XML配置文件过于臃肿,给后续的维护和升级带来一定困难。为此,Sping还提供了基于Annotation(注解)技术的全面支持,常见的注解如下:

项目 价格
@Component 用于描述Spring中的Bean,他是一个泛化的概念
@Repository 用于将数据访问层(DAO)的类标识为Spring中的Bean
@Service 用于业务层(Service)的类标识为Spring中的Bean
@Autowired 用于对Bean的属性变量、属性的setter方法及构造方法进行标注,配合对应的注解处理器完成Bean的自动配置工作
@Resource 其作用与Autowired一样。@Resource中有两个重要属性:name和type。Sping将name属性解析为Bean实例名称,type属性解析为Bean实例类型
@Qualifier 与@Autowired注解配合使用,会将默认的按Bean类型装配修改为按Bean的实例名称装配,Bean的实例名称有@Qualifier注解的参数指定

接下来通过一个实例来演示:

1、创建UserDao和UserService接口

public interface UserDao {
	public void save();
}
public interface UserService {
	public void save();
}

2、创建接口实现类并加入注解

@Repository("userDao")
public class UserDaoImpl implements UserDao{
	@Override
	public void save() {
		System.out.println("userDao---save---");
	}
}

3、编写service层并加入Service注解

@Service("userService")
public class UserServiceImpl implements UserService {

	@Resource(name="userDao")
	private UserDao userDao;
	@Override
	public void save() {
		//调用userDao中的save方法
		this.userDao.save();
		System.out.println("userService----save---");
	}
}

通过注解@Resource注入UseDao实例

3、创建controller类

@Controller("userController")
public class UserController {
	@Resource(name="userService")
	private UserService userService;
	public void save() {
		this.userService.save();
		System.out.println("userController----save-----");
	}
}

4、编写Bean.xml配置文件

	<!-- 使用context命名空间,在配置文件中开启响应的注解处理器 
	<context:annotation-config></context:annotation-config>
	<!-- 分别定义三个bean实例 -->
	<bean id="userDao" class="com.mq.annotation.UserDaoImpl"></bean>
	<bean id="userService" class="com.mq.annotation.UserServiceImpl"></bean>
	<bean id="userController" class="com.mq.annotation.UserController"></bean>

5、编写测试类

public class test {
	public static void main(String[] args) {
		// 定义配置文件的路径
		String xmlPath = "com/mq/annotation/Bean6.xml";
		// 加载配置文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		// 获取UserController实例
		UserController controller = (UserController) applicationContext.getBean("userController");
		// 调用UserController中的save()方法
		controller.save();
	}
}

方法二:同过包扫描,将这些组件纳入spring容器进行管理,在xml配置文件中进行如下配置:

<!-- 使用context命名空间,通知spring扫描指定包所有的bean类进行注解解析 -->
<context:component-scan base-package="com.mq.annotation"></context:component-scan>

不在需要一个一个bean进行配置

5、自动装配

所谓自动装配,就是将一个Bean自动的注入到到其他Bean的Property中。Spring的元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean。autowlre属性有5个值,其值及说明下表所示: