Spring基础特性总结一--核心组件Bean的使用
来源:互联网 发布:三星的电脑怎么样知乎 编辑:程序博客网 时间:2024/04/28 13:51
文章内容
0.Spring整体特性
1.Bean组件的介绍
2.Bean的定义、创建、解析
3.Bean的使用
0.Spring整体特性
Spring的整体架构可划分为两部分:核心组件和特性功能;
其中核心组件功能包括Core、Bean、Context,Core在Spring框架中用于提供基础操作的工具组件;Bean则用于封装Object来进行一系列操作和管理;Context是一个Bean关系的集合,也叫Ioc容器;
特性功能包括AOP、JDBC、Transaction等,主要是基于Spring三大核心组件之上实现的机制;
1.Bean组件的介绍
Bean作为Spring框架中最重要的组件,正是由于Bean的定义和实现才使得Spring可以实现Bean的自动创建和注入,简化了日常开发过程中对依赖关系的维护,都交由Spring来完成;
Bean是对Object的封装,使得Object的创建、销毁、具体操作都可以通过统一的接口来完成;
2.Bean的定义、创建、解析
2.1.Bean的定义
定义接口:org.springframework.beans.factory.config.BeanDefinition
从接口包含的方法可以看出,Bean封装了Object的类名、依赖、构造函数以及相关的配置信息(模式和作用域等);
2.2.Bean的创建
Spring Bean 的创建时典型的工厂模式,顶级接口是BeanFactory;
非顶级的BeanFactory,如ListableBeanFactory、HierarchicalBeanFactory、AutowireCapableBeanFactory;
需要说明的是,这些非顶级的接口定义了新生成的Bean的不同方便的特性;例如,如果这个Bean是由实现了ListableBeanFactory接口的BeanFactory生成的,那么他是可列表的,如果这个BeanFactory还实现了AutowireCapableBeanFactory,那么这个Bean将有自己的装配规则;而在默认情况下,BeanFactory的最终实现类为DefaultListableBeanFactory,而它实现了所有接口,所以通过默认的BeanFactory产生的Bean具有Bean的几乎所有特性
默认BeanFactory实现:org.springframework.beans.factory.support.DefaultListableBeanFactory
分析其中通过类类型获取Bean的方法:
(Assert是一个可以借鉴的设计,文章最后介绍)
public <T> T getBean(Class<T> requiredType) throws BeansException { //字段验证 Assert.notNull(requiredType, "Required type must not be null"); //获取Bean的名称 String[] beanNames = getBeanNamesForType(requiredType); if (beanNames.length > 1) { ArrayList<String> autowireCandidates = new ArrayList<String>(); for (String beanName : beanNames) { if (getBeanDefinition(beanName).isAutowireCandidate()) { autowireCandidates.add(beanName); } } if (autowireCandidates.size() > 0) { beanNames = autowireCandidates.toArray(new String[autowireCandidates.size()]); } } if (beanNames.length == 1) { return getBean(beanNames[0], requiredType); } else if (beanNames.length == 0 && getParentBeanFactory() != null) { return getParentBeanFactory().getBean(requiredType); } else { throw new NoSuchBeanDefinitionException(requiredType, "expected single bean but found " + beanNames.length + ": " + StringUtils.arrayToCommaDelimitedString(beanNames)); }}//逐层向上分析//AbstractBeanFactory::---->getBean()--->doGetBean()--->getSingleton()--->默认Singleton模式,通过返回的实例是否为null判断是否获取Prototype实例//DefaultSingletonBeanRegistry::--->getSingleton()//典型的单例模式protected Object getSingleton(String beanName, boolean allowEarlyReference) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { ObjectFactory singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null);}
2.3.Bean的解析
上面已经讲过Bean的定义和创建,BeanFactory通过BeanDefinition生成对应的Bean实例;
上图,给出了Bean创建的过程,Bean的解析主要完成对XML中的Bean相关节点的识别和转换为对应的BeanDefinition对象,这块的工作是很清晰的,只是设计到XML解析的相关操作,会比较复杂;整个解析过程主要通过下图中的类来完成:
3.Bean的使用
我们在使用Bean时主要关心的如何配置一个Bean,是的Context在初始化时能正确的初始化一个Bean;
首先,IoC容器Bean配置3种方式:
①基于XML文件进行配置(XML文件)
②基于注解进行配置(spring-aop)
③基于java进行配置(利用几个特殊的注解、不常用)
其次,要配置一个完整的Bean,只要关注以下几个方面:依赖注入的方式(初始化)、复杂Bean的配置和Bean的获取(装配);
3.1.依赖注入
依赖注入的方式主要有三种(最常使用的是① ②):
①使用set方法注入
②使用构造器注入
③接口注入
首先创建一个简单的Bean:
public class People { private String name; private String sex; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString(){ return "{ name:"+getName()+";sex:"+getSex()+";age:"+getAge()+"; }"; }}
测试代码:
//获取ioc容器ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");//根据id获取到bean对象Object bean = ioc.getBean("people");System.out.println(bean);
3.1.1.使用Set方法注入
通过Set注入是指通过属性的set方法初始化Context中的Bean:
<bean....> <property name="set方法后面部分名称" value="初始化的值"></property></bean>
具体配置实例:
<!-- applicationContext.xml --><bean id="people" class="com.aaron.spring.bean.People"> <property name="name" value="小明"></property> <property name="sex" value="man"></property> <property name="age" value="18"></property></bean>
3.1.2.使用构造器注入
通过构造函数注入和通过setter的方法的主要不同是Bean需要构造函数;
在People中增加构造函数:
public People(){}public People(String name, String sex, int age){ this.name = name; this.sex = sex; this.age = age;}
<bean id="people2" class="com.aaron.spring.bean.People"> <constructor-arg value="小王" name="name"/> <constructor-arg value="man" name="sex"/> <constructor-arg value="18" name="age"/></bean>
需要注意的是:
setter方法调用的是无参构造函数,通过构造函数注入的方式,需要参数和构造函数一一对应,可以通过index/type/name来配置参数之间的对应关系;
其次通过setter和构造函数的方式在调用的时间不同,setter是先创建实例,在调用setter方法,构造函数的方式则是在构造函数被调用时进行初始化;
推荐使用,setter的方式进行注入,通过构造函数的方式在存在复杂依赖关系的时候配置会非常复杂;
3.1.3.接口注入
接口注入的方式使用很少,主要通过
Context.lookup(ServletContext.getXXX)
获取当前COntext中符合条件的接口的实现,并进行实例化;这种方式和Context当前的环境有关,不同的Context获取到的对应实现类可能是不同的;
3.2.复杂Bean的配置
复杂Bean的配置包括:Bean之间关系的配置以及集合类型属性的赋值;
3.2.1.Bean之间关系:继承和依赖
如果存在两个Bean的大部分属性一致,可以通过继承来减少重复配置相同参数:
<bean id="people3" class="com.aaron.spring.bean.People" parent="people"> <property name="name" value="小红"></property></bean>
依赖关系主要用于一个Bean如果有使用其他的Bean,则必须创建这样的依赖关系,在Context初始化时检查对应ID的Bean是否存在:
<bean id="people3" class="com.aaron.spring.bean.People" parent="people" depends-on="people4"><property name="name" value="小红"></property></bean>Exception:org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'people4' is defined
3.2.2.集合类型属性的赋值
举个例子就行了
private List<Book> list;
<property name="list"> <!-- 给List集合属性赋值 --> <list> <!-- 可以是内部bean --> <bean p:title="内部Bean" class="com.atguigu.beans.Book"></bean> <!-- 可以是String字符串 --> <value>String字符串</value> <!-- 可以是一个引用 --> <ref bean="book01"/> </list></property>
private Map<String,Car> map;
<property name="map"> <map> <entry key="免费书籍" value-ref="book01"></entry> <entry key="2"> <bean p:title="鹿鼎记(内部bean)" class="com.atguigu.beans.Book"></bean> </entry> <entry key="3" value="String字符串"></entry> </map></property>
private Properties prop;
<property name="properties"> <props> <prop key="url">jdbc:mysql//localhost:8080/test</prop> <prop key="root">root</prop> <prop key="password">123456</prop> </props> </property>
3.3.Bean的获取
相面主要讨论如何虫Context中获取Bean,要获取Bean首先需要区分id和name的区别,id有要个的命名规范,且不可重复;name可以使用更多的字符且可以重复,配置文件中的同名Bean后面的会覆盖前面的,name默认为类的全名;所以,一般使用id来标识一个唯一的Bean;
获取Bean的方法主要有两种:显式调用getBean和注解的方式;
3.3.1.通过getBean获取Bean
主要是通过类名,id和name,其中参数name包括id和name;
3.3.1.通过注解获取Bean
使用Spring的注解方式配置,需要引入spring-aop包,关键的注解为
@Autowired
* @Qualifier(“Bean ID”)*
@Autowired:通过匹配当前的类型找到对应的Bean,并进行初始化赋值;默认required=true,即如果找不到对应的Bean则报错;
@Qualifier(“Bean ID”):用于指定Bean的ID,用于有多个实现类的情况唯一标识一个Bean,如果不存在冲突则可以不设置;
使用的方式主要有以下两种:
首先添加xml配置:
<context:component-scan base-package="Service包名"></context:component-scan>
新增TestService类,用于获取Bean
@Service("peopleService")public class TestService { //方式一 @Autowired(required=false) @Qualifier("people") private People people1; private People people2; public People getPeople1() { return people1; } public void setPeople1(People people1) { this.people1 = people1; } //方式二 @Autowired public void setPeople2(@Qualifier("people")People people2) { this.people2 = people2; } public People getPeople2(){ return this.people2; }}
Main方法使用:
TestService service = (TestService) ioc.getBean("peopleService");System.out.println(service.getPeople1());
参考文章:
(Spring 框架的设计理念与设计模式分析–许 令波)[https://www.ibm.com/developerworks/cn/java/j-lo-spring-principle]
- Spring基础特性总结一--核心组件Bean的使用
- Spring基础特性总结二 --- 核心组件Core以及Resource的设计
- Spring核心组件之Bean
- spring bean的使用总结
- Spring核心组件bean、context、core
- Spring的Bean组件
- Spring的核心容器Bean的基础知识(一)
- SPRING BEAN的基础
- Spring之Bean总结(一)
- Spring核心组件详解(Bean、Context、Core)
- Spring Mvc 的核心组件
- Spring基础学习教程(Spring之核心容器bean)-06
- spring核心:bean工厂的装配 1
- spring核心:bean工厂的装配 2
- spring核心:bean工厂的装配 3
- spring核心:bean工厂的装配 4
- spring核心:bean工厂的装配 5
- spring核心:bean工厂的装配 6
- 面向对象中装饰模式的理解
- Python实现感知器
- 理解Oauth2.0原理的好文章(转自阮一峰老师)
- ios libfdk-aac encode
- cmake项目引入dlib方法
- Spring基础特性总结一--核心组件Bean的使用
- JQuery与DOM相互转换
- spark学习-28-Spark数据倾斜问题
- Android 中ContentProvider的用法及用ContentProvider访问联系人
- 选择测试
- git-切换远程的分支
- Java Date函数的时间格式
- Spring多数据源配置系列(三)——读写分离
- 异常