Spring-bean
Bean配置
Spring可以看做是一个大型的工厂,用于生产和管理Spring容器中的Bean。要使用这个工厂生产和管理Bean,则需要将Bean配置在Spring的配置文件中。Spring支持XML与properties两种格式的配置文件,这里我采用XML的形式。
先来了解一个bean的常用属性
属性 | 作用 |
---|---|
id | Bean在BeanFactory中的唯一标识,要想获取Bean实例,则需要Id |
class | Bean的具体实现类,使用类名 |
scope | Bean的作用域,当为singleton时,SpringIOC容器仅生成和管理一个Bean实例,当为prototype时,每次请求则会创建一个。 |
标签的子元素,使用构造器方法注入时,指定构造器的参数。index属性指定参数的序号,ref属性指定与其他Bean的引用关系,type属性指定参数类型,value指定参数的常量值 | |
元素的子元素,用于设置一个值。name属性为Bean实例的属性名称,value属性为Bean的属性值,ref属性指定属性与其他Bean的引用关系 | |
元素的子元素,用于封装Map类型的依赖注入 | |
元素的子元素,用于封装Set类型的依赖注入 | |
元素的子元素,用于封装List类型的依赖注入 |
Bean的实例化
为什么需要实例化?如果我们想使用一个对象,则这个对象就需要实例化。在Spring中,想使用一个Bean,则需要实例化。实例化的方式有三种,即构造方法实例化,静态工厂实例化和实例工厂实例化。
构造方法实例化
BeanClass.java
package instance;
public class BeanClass {
public String name;
public BeanClass(){
name="构造方法实例化";
}
public BeanClass(String names){
name=names;
}
}
package test;
//测试类
import instance.BeanClass;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanClass o = (BeanClass)context.getBean("beanClass");
System.out.println(o+o.name);
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanClass" class="instance.BeanClass"/>
</beans>
目录
运行结果为
静态工厂实例化
新建一个类,在类中使用静态方法创建想实例化的Bean,从而达到静态工厂实例化。在配置Bean时,class属性指定的时新建的静态工厂类,因为是让静态工厂去实例化这个Bean,而还需用factory-method属性去指定使用了静态工厂类中哪个方法去实例化了想实例化的Bean。
新建一个静态工厂类
package instance;
public class BeanStaticClass {
private static BeanClass beanInstance=new BeanClass("静态方法实例化");
public static BeanClass beanInstance(){ ///实例化实例的方法
return beanInstance;
}
}
在配置文件中加入
<bean id="instanceClass" class="instance.BeanStaticClass" factory-method="beanInstance"/>
测试一下
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanClass o = (BeanClass)context.getBean("instanceClass");
System.out.println(o+o.name);
}
}
结果
实例工厂实例化
新建一个类,在类中使用方法创建想实例化的Bean,从而达到实例工厂实例化。在配置Bean时,,用factory-bean去指定实例化工厂,因为是让实例工厂去实例化这个Bean,而还需用factory-method属性去指定使用了实例工厂类中哪个方法去实例化了想实例化的Bean。
实例工厂类
package instance;
public class BeanInstanceClass {
public BeanClass beanInstanceClass(){
return new BeanClass("调用实例工厂方法实例化Bean");
}
}
配置文件
<bean id="instanceFactory" class="instance.BeanInstanceClass"/> <!-- 实例工厂-->
<bean id="instanceClass" class="instance.BeanInstanceClass" factory-bean="instanceFactory" factory-method="beanInstanceClass"/>
测试类
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BeanClass o = (BeanClass)context.getBean("instanceClass");
System.out.println(o+o.name);
}
}
结果
bean的生命周期
我对bean生命周期的理解是这样的,由于scope的值可以为singleton时,即只会创建一个Bean实例,则Spring可以对其生命周期进行追踪,但是当scope的值为prototype时,由于每次请求都会创建一个新的bean,所以Spring只负责创建,创建以后则不会对Bean的=进行管理。
当创建Bean之前,可以先对其初始化,在Bean销毁的时候,也可以对其自定义销毁。举个例子
BeanLife.java
package instance;
public class BeanLife {
public void initBefore(){
System.out.println("执行自定义的初始化方法");
}
public void destroyAfter(){
System.out.println("自定义销毁");
}
}
xml文件
<bean id="beanLife" class="instance.BeanLife" init-method="initBefore" destroy-method="destroyAfter"/>
- init-method指定了在得到这个Bean之前需要执行的方法
- destroy-method指定了在销毁这个Bean之前需要执行的方法
测试函数
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("获得Bean前");
BeanLife o = (BeanLife)context.getBean("beanLife");
System.out.println("获得Bean后");
context.close();
}
}
Bean的装配方式
之前一直不理解,Bean的实例化与Bean的装配有什么区别,通过大量的查阅资料,算是理解了。实例化只是给Bean开辟了空间,而装配则是给Bean的属性赋值。在Spring中,支持xml与注解两种方式对Bean的装配。而对Bean装配的过程,也就是对Bean依赖注入的过程。
基于XML方式的装配
基于XML的注入方式,在前面的文章我也大概提到过,有两种方式,一种是构造器注入,一种是Setter方法注入。
-
使用构造器注入,则需要带参数的构造方法,这是非常重要的。
-
使用setter方法注入,则需要无参构造方法,以及set方法。
举个例子
User.java
package pojo;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class User {
private String name;
private List<String> hobby;
private Map<String,String> family;
private Set<String> like;
private String[] array;
public User() {
}
public User(String name, List<String> hobby, Map<String, String> family, Set<String> like, String[] array) {
this.name = name;
this.hobby = hobby;
this.family = family;
this.like = like;
this.array = array;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getHobby() {
return hobby;
}
public void setHobby(List<String> hobby) {
this.hobby = hobby;
}
public Map<String, String> getFamily() {
return family;
}
public void setFamily(Map<String, String> family) {
this.family = family;
}
public Set<String> getLike() {
return like;
}
public void setLike(Set<String> like) {
this.like = like;
}
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", hobby=" + hobby +
", family=" + family +
", like=" + like +
", array=" + Arrays.toString(array) +
'}';
}
}
<!--使用构造器依赖注入-->
<bean id="userCon" class="pojo.User">
<constructor-arg name="name" value="cx"/>
<constructor-arg name="family">
<map>
<entry key="father" value="cc"/>
<entry key="mother" value="xx"/>
</map>
</constructor-arg>
<constructor-arg name="array">
<array>
<value>arry1</value>
<value>arry2</value>
</array>
</constructor-arg>
<constructor-arg name="hobby">
<list>
<value>list1</value>
<value>list2</value>
</list>
</constructor-arg>
<constructor-arg name="like">
<set>
<value>set1</value>
<value>set2</value>
</set>
</constructor-arg>
</bean>
<!--使用setter方法注入-->
<bean id="beanSetter" class="pojo.User">
<property name="name" value="lc"/>
<property name="hobby">
<list>
<value>list1_setter</value>
<value>list2_setter</value>
</list>
</property>
<property name="family">
<map>
<entry key="father" value="cc_setter"/>
<entry key="mom" value="xx_setter"/>
</map>
</property>
<property name="like">
<set>
<value>set1_setter</value>
<value>set2_setter</value>
</set>
</property>
<property name="array">
<array>
<value>arry1_setter</value>
<value>arry2_setter</value>
</array>
</property>
</bean>
测试函数
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Object con = (User)context.getBean("userCon");
User o = (User)context.getBean("beanSetter");
System.out.println(con.toString());
System.out.println(o.toString());
}
基于注解的装配
常见的注解
注解 | 功能 |
---|---|
@Component | 表示为Spring的一个组件对象(bean),可以作用在任何层次上 |
@Controller | 标注一个控制器类,功能与@Component相同 |
@Service | 标注一个业务逻辑组件类,功能与@Component相同 |
@Repository | 标注数据访问层,功能与@Component相同 |
@Autowired | 可以对类成员变量,方法以及构造方法进行标注,完成自动装配。默认按照类型进行装配 |
@Resource | 与@Autowried功能相同,唯一的区别是默认按照名称进行装配 |
@Qualifier | 与注解@Autowired配合使用,当注解@Autowired需要按照名称进行装配时,可以@Qualifier来指定名称 |
在Spring中,还需要引入context命名空间,来扫描标注的组件对象。
<context:component-scan base-package="annotation"/>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
完整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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<context:component-scan base-package="annotation"/>
<bean id="beanClass" class="instance.BeanClass"/>
<bean id="staticClass" class="instance.BeanStaticClass" factory-method="beanInstance"/>
<bean id="instanceFactory" class="instance.BeanInstanceClass"/> <!-- 实例工厂-->
<bean id="instanceClass" class="instance.BeanInstanceClass" factory-bean="instanceFactory" factory-method="beanInstanceClass"/>
<bean id="beanLife" class="instance.BeanLife" init-method="initBefore" destroy-method="destroyAfter"/>
<!--使用构造器依赖注入-->
<bean id="userCon" class="pojo.User">
<constructor-arg name="name" value="cx"/>
<constructor-arg name="family">
<map>
<entry key="father" value="cc"/>
<entry key="mother" value="xx"/>
</map>
</constructor-arg>
<constructor-arg name="array">
<array>
<value>arry1</value>
<value>arry2</value>
</array>
</constructor-arg>
<constructor-arg name="hobby">
<list>
<value>list1</value>
<value>list2</value>
</list>
</constructor-arg>
<constructor-arg name="like">
<set>
<value>set1</value>
<value>set2</value>
</set>
</constructor-arg>
</bean>
<!--使用setter方法注入-->
<bean id="beanSetter" class="pojo.User">
<property name="name" value="lc"/>
<property name="hobby">
<list>
<value>list1_setter</value>
<value>list2_setter</value>
</list>
</property>
<property name="family">
<map>
<entry key="father" value="cc_setter"/>
<entry key="mom" value="xx_setter"/>
</map>
</property>
<property name="like">
<set>
<value>set1_setter</value>
<value>set2_setter</value>
</set>
</property>
<property name="array">
<array>
<value>arry1_setter</value>
<value>arry2_setter</value>
</array>
</property>
</bean>
</beans>
- 忽略配置的bean,此处没用到
TestDao.java
package annotation.dao;
public interface TestDao {
public void print();
}
package annotation.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class TestDaoImp implements TestDao {
public void print() {
System.out.println("TestDaoImp");
}
}
TestService.java
package annotation.service;
public interface TestService {
public void print();
}
TestServiceImp.java
package annotation.service;
import annotation.dao.TestDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import test.Test;
@Service
public class TestServiceImp implements TestService {
@Autowired
@Qualifier(value = "testDaoImp")
private TestDao testDao;
public void print() {
testDao.print();
System.out.println("TestServiceImp");
}
}
TestController.java
package annotation.controller;
import annotation.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;
@Controller
public class TestController {
@Resource
private TestService testService;
public void print(){
testService.print();
}
}
测试类
package test;
import annotation.controller.TestController;
import annotation.service.TestService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.User;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
TestController con = (TestController)context.getBean("testController");
con.print();
TestService testService = (TestService)context.getBean("testServiceImp");
testService.print();
}
}
otation.service.TestService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import pojo.User;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
TestController con = (TestController)context.getBean(“testController”);
con.print();
TestService testService = (TestService)context.getBean(“testServiceImp”);
testService.print();
}
}