本篇文章主要介绍Bean相关的知识点,让我们进一步去理解Spring 中 Bean的概念。
目录
1 Bean 基础
1.1 Bean的名称-标识
1.2 Bean的创建方式
1.2.1 构造方法创建
1.2.2 工场方法创建
1.2.2.1 静态工场
1.2.2.2 非静态工场
2 依赖注入(Dependency Injection)
2.1 构造函数
2.1.1 直接注入不需要强调类型,名字或者下标
2.1.2 使用下标
2.1.3 使用type
2.1.4 使用name
2.1.5 使用c:{}=xx
2.2 setter 注入
2.2.1 property方法
2.2.2 p:{}方法
3 bean中其它概念
3.1 depends-on
3.2 懒加载 Lazy-initialized Beans
3.3 Lookup 查找型方法注入
3.4 方法替换
3.5 Bean 的Scopes
3.6 父级 Bean
4 Bean的自定义特性
4.1 Lifecycle Callbacks
4.1.1 InitializingBean
4.1.2 DisposableBean
4.1.3 Custom init() 和 destory()
4.1.4 @PostContruct @PreDestroy
4.1.5 SmartLifecycle
4.2 ApplicationContextAware and BeanNameAware
4.2.1 ApplicationContextAware
4.2.2 BeanNameAware
4.3 其它Aware接口
4.3.1 ApplicationEventPublisherAware
4.3.2 BeanClassLoaderAware
4.3.3 BeanFactoryAware
4.3.4 BootstrapContextAware
4.3.5 LoadTimeWeaverAware
4.3.6 MessageSourceAware
4.3.7 NotificationPublisherAware
4.3.8 ResourceLoaderAware
4.3.9 ServletConfigAware
4.3.10 ServletContextAware
1 Bean 基础
1.1 Bean的名称-标识
每个bean都有一个或多个标识符。这些标识符在bean的容器中必须是唯一的。一个bean通常只有一个标识符。当然,如果需要多个,则可以引用别名。
在xml
中可以用id
和 name
来定义bean的标识,但是id
只能设置一个名称,而name
可以设置多个(用,
号或者;
号或者空格
隔开)
<bean id="observer" name="observer_a,observer_b observer_c" class="com.lykos.ioc.chapter2.Observer"/>
不仅如此,创建bean的别名还有一种方式就是用alias
<alias name="observer_c" alias="observer_d"/>
<alias name="observer_c" alias="observer_e"/>
1.2 Bean的创建方式
bean支持构造方法
和工场方法创建
1.2.1 构造方法创建
当然工场方法创建与构造方法创建使用方法一样
@Data
public class Observer {
//无参构造方法
public Observer(){}
//有参构造方法
@ConstructorProperties({"name"})
public Observer(String name){
this.name = name;
}
private String name;
}
<!-- 使用无参构造方法,创建-->
<bean id="observer_constructor" class="com.lykos.ioc.chapter2.Observer">
</bean>
<!-- 使用有参构造方法:属性名创建-->
<bean id="observer_constructor_arg" class="com.lykos.ioc.chapter2.Observer">
<constructor-arg name="name" value="observer_constructor_arg_name"/>
</bean>
<!-- 使用有参构造方法:下标创建-->
<bean id="observer_constructor_arg_index" class="com.lykos.ioc.chapter2.Observer">
<constructor-arg index="0" value="observer_constructor_arg_name_index"/>
</bean>
1.2.2 工场方法创建
支持静态方法和非静态方法
1.2.2.1 静态工场
public class ObserverStaticFactory {
public static Observer createObserver(){
return new Observer();
}
}
1.2.2.2 非静态工场
public class ObserverNonStaticFactory {
public Observer createObserver(){
return new Observer();
}
}
<!-- 静态工场方法创建-->
<bean id="observer_from_static_factory" class="com.lykos.ioc.chapter2.ObserverStaticFactory" factory-method="createObserver"></bean>
<!-- 非静态工场方法创建-->
<bean id="observerFactory" class="com.lykos.ioc.chapter2.ObserverNonStaticFactory"></bean>
<bean id="observer_from_non_static_factory_b" factory-bean="observerFactory" factory-method="createObserver">
2 依赖注入(Dependency Injection)
依赖注入分为构造函数
和setter
两种方式
2.1 构造函数
构造函数注入属性时有多种方式,分别为
2.1.1 直接注入不需要强调类型,名字或者下标的
这种注入方式的前题是参数中没有歧义,不是基本类型
public class ConstructA {
private ConstructB constructB;
private ConstructC constructC;
public ConstructA(ConstructB constructB,ConstructC constructC){
this.constructB = constructB;
this.constructC = constructC;
}
}
public class ConstructB {
}
public class ConstructC {
}
<bean id="constructA" class="com.lykos.ioc.chapter2.ConstructA">
<!--此处与顺序无关,也不需要指定名称和类型-->
<constructor-arg ref="constructB"/>
<constructor-arg ref="constructC"/>
</bean>
<bean id="constructB" class="com.lykos.ioc.chapter2.ConstructB"/>
<bean id="constructC" class="com.lykos.ioc.chapter2.ConstructC"/>
2.1.2 使用下标
public class ConstructD {
private int age;
private String name;
public ConstructD(int age,String name){
this.age = age;
this.name = name;
}
}
2.1.2.1 默认情况下就是配置顺序
<!-- 不用指定下标,默认就是顺序就是我们配置顺序-->
<bean id="constructD" class="com.lykos.ioc.chapter2.ConstructD">
<constructor-arg value="2"/>
<constructor-arg value="this name"/>
</bean>
2.1.2.2 使用index指定下标
<!-- 使用index指定下标,此时与我们配置的顺序无关,顺序可以随变-->
<bean id="constructD_index" class="com.lykos.ioc.chapter2.ConstructD">
<constructor-arg index="1" value="this name 1"/>
<constructor-arg index="0" value="2"/>
</bean>
2.1.3 使用type
<!-- 使用type,此时与我们配置的顺序无关,顺序可以随变-->
<bean id="constructD_type" class="com.lykos.ioc.chapter2.ConstructD">
<constructor-arg type="java.lang.String" value="this name 1 type"/>
<constructor-arg type="int" value="112"/>
</bean>
2.1.4 使用name
使用name是需要用到@ConstructorProperties
注解。因为我们我们编译之后参数名会变成var1
等,无法获取真实参数名,所以我们需要注解来标注。
//此处需要ConstructorProperties注释
@ConstructorProperties({"age", "name"})
public ConstructD(int var1, String var2) {
this.age = var1;
this.name = var2;
}
2.1.5 使用c:{}=xx
在bean标签中使用c:{paramName}=xxx
方式。要使用此方式配置文件中必须添加
xmlns:c="http://www.springframework.org/schema/c"
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 使用c:{},此时与我们配置的顺序无关,顺序可以随变-->
<bean id="constructD_c_name" class="com.lykos.ioc.chapter2.ConstructD" c:name="cName" c:age="123"/>
</beans>
2.2 setter 注入
setter注入是在通过构造函数
或者工场方法
实例化对象后,使用对象setter方法调用的。
2.2.1 property方法
public class SetterA {
private String age;
private String name;
public void setAge(String age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
}
<bean id="setterA" class="com.lykos.ioc.chapter2.SetterA">
<property name="age" value="18"></property>
<property name="name" value="lykos"></property>
</bean>
2.2.2 p:{}方法
在bean标签中使用p:{propertyName}=xxx
方式。要使用此方式配置文件中必须添加
xmlns:p="http://www.springframework.org/schema/p"
<bean id="setterB" class="com.lykos.ioc.chapter2.SetterA" p:age="17" p:name="pName"/>
3 bean中其它概念
3.1 depends-on
实例化当前bean时需要依赖的对象,同时也决定了初始化
和销毁
顺序。多个用,
隔开
<bean id="setterC" depends-on="setterB,setterA" class="com.lykos.ioc.chapter2.SetterA" p:age="19" p:name="dependName"/>
3.2 懒加载 Lazy-initialized Beans
正常情况在,IoC容器会在程序启动时全部初始化好singleton
的对象,当然我们也可以使用lazy-init=true
在指定当前对象不用着急加载,只需要在我们第一次使用时(也就是第一次getBean的时候)在初始化
<bean id="setterD" lazy-init="true" class="com.lykos.ioc.chapter2.SetterA"/>
我们也可以在beans
上设置default-lazy-init="true"
使其包含的所有bean默认都懒加载的
3.3 Lookup 查找型方法注入
这个查找型方法,可以理解为就是一个工场方法,他主要是搭配原型-prototype
对象一起使用。主要原理是使用了CGLIB
库生成字节码来动态生成覆盖该方法的子类来实现的。因此我们必须要先创建一个抽象类(抽象方法)或者接口(方法签名)
public abstract class LookUp {
public abstract SetterA getSetterA();
}
或者
public interface LookUp {
SetterA getSetterA();
}
<!-- 这里必须是scope="prototype" -->
<bean id="setter_to_lookup" scope="prototype" class="com.lykos.ioc.chapter2.SetterA" p:age="17" p:name="pName"/>
<bean id="lookup" class="com.lykos.ioc.chapter2.LookUp">
<!--lookup-method 定义后,每次getSetterA都会是一个新的对象-->
<lookup-method name="getSetterA" bean="setter_to_lookup"></lookup-method>
</bean>
3.4 方法替换
就是写一个通用方法替换原有的方法
定义一个被替换的方法
public class MethodReplace {
public String say(String message){
return message;
}
}
定义一个替换方法,必须实现MethodReplacer
接口
public class MyMethodReplacer implements MethodReplacer {
@Override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
System.out.println("do your thing");
//不能执行method.invoke(obj,args)
return null;
}
}
使用
<bean id="methodReplace" class="com.lykos.ioc.chapter2.MethodReplace">
<!-- 使用replaced-method替换原有的方法-->
<replaced-method name="say" replacer="myMethodReplacer"></replaced-method>
</bean>
<bean id="myMethodReplacer" class="com.lykos.ioc.chapter2.MyMethodReplacer"></bean>
3.5 Bean 的Scopes
spring ioc中常用的是singleton
和prototype
。而singleton
是默认的。
singleton 在ioc容器中有且仅有一个实例对象
prototype 在ioc容器中是多实例,也就是每当getBean时都会创建一个新的对象
当然在ioc中还有request
,session
,application
,websocket
不过这些scope只能在web应用容器中使用。
通常我们用scope="prototype"
来设置bean的scope
<bean id="xxx" class="xxx" scope="prototype" />
3.6 父级 Bean
xml
中也可以用 <bean parent="parentBean">
来继成父类bean的相关配置信息,例如:属性
,构造参数
,初始化方法
等
parent既可以是具体的bean也可以是用于 <bean abstract="true">
定义的抽象bean。
abstract=true 意味着在定义此类bean时我们可以不需要用class指定具体类限定名,当然容器在初始化过程中也会跳过带有abstract=true属性相关bean的实例化。
<bean id="parentBean2" abstract="true">
<property name="name" value="parentBean2"></property>
<property name="age" value="18"></property>
</bean>
子类使用
<bean id="childBean" parent="parentBean2" class="com.lykos.ioc.chapter2.ChildBean">
<property name="desc" value="this is child"></property>
</bean>
此处com.lykos.ioc.chapter2.ChildBean需要有name和age属性
public class ChildBean {
private String name;
private int age;
private String desc;
}
注意:子类也可以覆盖父类配置
<bean id="childBean2" parent="parentBean2" class="com.lykos.ioc.chapter2.ChildBean">
<property name="name" value="coverParentName"></property>
<property name="desc" value="this is child"></property>
</bean>
4 Bean的自定义特性
spring提供了许多接口,用于自定义Bean的特性
4.1 Lifecycle Callbacks
从spring 2.5开始我们有三个选项来控制bean的生命周期行为
The
InitializingBean
andDisposableBean
callback interfacesCustom
init()
anddestroy()
methodsThe
@PostConstruct
and@PreDestroy
annotations. You can combine these mechanisms to control a given bean.
4.1.1 InitializingBean
实现此接口后。当容器中所有必要属性设置完成后,spring容器会回调afterPropertiesSet
方法
定义initializingBean
public class MyInitializingBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("所有属性设置完成!");
}
}
注册initializingBean
<bean id="myInitializingBean" class="com.lykos.ioc.chapter2.MyInitializingBean"></bean>
4.1.2 DisposableBean
实现此接口后,当容器被销毁后,可以得到回调。当然如果需要获取回调,我们还必须向容器中注册回调钩子。web容器中默认已加上
注册回调钩子
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
// add a shutdown hook for the above context...
ctx.registerShutdownHook();
创建disposableBean
public class MyDisposableBean implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("destroy");
}
}
注册disposableBean
<bean id="myDisposableBean" class="com.lykos.ioc.chapter2.MyDisposableBean"></bean>
4.1.3 Custom init() 和 destory()
自定义初始化方法和销毁方法
在xml
中可以在<beans default-init-method="init" default-destroy-method="destory">
全局设置多个bean的初始化和销毁方法。当然也可以在<bean init-method="" destroy-method=""/>
中覆盖
全局的配置
当然在annotation
中可以使用@Bean(initMethod = "",destroyMethod = "")
设置
4.1.4 @PostContruct @PreDestroy
这两个都是在使用annotation
时使用
4.1.5 SmartLifecycle
在讲解SmartLifecycle之前我们先认识一下
Lifecycle 接口可以为任何对象提供基本的生命周期方法
Phased 接口在多个SmartLifecycle中决定执行顺序
4.1.5.1 Lifecycle
public interface Lifecycle {
void start();
void stop();
boolean isRunning();
}
4.1.5.2 Phased
public interface Phased {
int getPhase();
}
4.1.5.3 SmartLifecycle
public interface SmartLifecycle extends Lifecycle, Phased {
boolean isAutoStartup();
void stop(Runnable callback);
}
可以看到SmartLifecycle
继承了Lifecycle
,Phased
接口
下面根据一个自己实现了SmartLifecycle接口的类做详细说明
public class LifecycleBean implements SmartLifecycle {
/**
* 当所有对象已被实例化和初始化之后,将调用该方法
* 默认生命周期处理器将检查每个SmartLifecycle对象的
* isAutoStartup()方法和isRunning()方法返回值,如果都为true则被调用。
*/
@Override
public void start() {
System.out.println("LifecycleBean start");
}
/**
* isRunning()方法返回值为true则被调用。
*/
@Override
public void stop() {
System.out.println("LifecycleBean stop");
}
/**
* 1. 只有该方法返回false时,start方法才会被执行
* 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
*/
@Override
public boolean isRunning() {
return true;
}
/**
* 如果工程中有多个实现接口SmartLifecycle的类,则这些类的start的执行顺序按getPhase方法返回值从小到大执行
* stop方法的执行顺序则相反,getPhase返回值较大类的stop方法先被调用,小的后被调用。
*/
@Override
public int getPhase(){
return 1;
}
/**
* 只有返回true star才会执行
* @return
*/
@Override
public boolean isAutoStartup() {
return true;
}
}
4.2 ApplicationContextAware and BeanNameAware
4.2.1 ApplicationContextAware
此接口提供了为对象注入ApplicationContext
的能力
public interface ApplicationContextAware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
4.2.2 BeanNameAware
在填充好bean属性之后且初始化回调(InitializingBean,Custom init)之前调用
public interface BeanNameAware {
void setBeanName(String name) throws BeansException;
}
4.3 其它Aware接口
spring还提供了多种Aware回调接口,这些接口使Bean向IoC容器表示它们需要某种基础结构依赖性
4.3.1 ApplicationEventPublisherAware
事件发布
public interface ApplicationEventPublisherAware extends Aware {
void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher);
}
4.3.2 BeanClassLoaderAware
public interface BeanClassLoaderAware extends Aware {
void setBeanClassLoader(ClassLoader classLoader);
}
4.3.3 BeanFactoryAware
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
4.3.4 BootstrapContextAware
public interface BootstrapContextAware extends Aware {
void setBootstrapContext(BootstrapContext bootstrapContext);
}
4.3.5 LoadTimeWeaverAware
public interface LoadTimeWeaverAware extends Aware {
void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver);
}
4.3.6 MessageSourceAware
public interface MessageSourceAware extends Aware {
void setMessageSource(MessageSource messageSource);
}
4.3.7 NotificationPublisherAware
public interface NotificationPublisherAware extends Aware {
void setNotificationPublisher(NotificationPublisher notificationPublisher);
}
4.3.8 ResourceLoaderAware
public interface ResourceLoaderAware extends Aware {
void setResourceLoader(ResourceLoader resourceLoader);
}
4.3.9 ServletConfigAware
public interface ServletConfigAware extends Aware {
void setServletConfig(ServletConfig servletConfig);
}
4.3.10 ServletContextAware
public interface ServletContextAware extends Aware {
void setServletContext(ServletContext servletContext);
}
4. 感谢
感谢各位老铁花时间观看!
欢迎留言指正!
内容持续更新!