Spring容器
手写Autowired注解
/** 实现spring的Autowired注解 **/
//运行时触发
@Retention(RetentionPolicy.RUNTIME)
//作用于变量
@Target(ElementType.FIELD)
public @interface Autowired {
}
public class UserController {
@Autowired
private UserService userService;
/**
* 不注入
* 私有属性,编译器就放到访问标志符
*/
private Integer integer;
private String name;
public UserService getUserService() {
return userService;
}
//get,set...
}
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.stream.Stream;
/**
* Title:反射实现ioc
* Description:
*
* spring可扩展:
* 容器初始化前扩展
* 对象创建前扩展
* 不同阶段监听事件
* 面向接口编程
*
* @author WZQ
* @version 1.0.0
* @date 2021/1/27
*/
public class Test {
public static void main(String[] args) throws Exception{
//反射测试
UserController userController = new UserController();
UserService userService = new UserService();
Class<? extends UserController> clazz = userController.getClass();
//Declared可以拿到private、default、protected、public
//但是只能是自己类的,父类的属性拿不到
//解决方法:
//一、getFields(),通过set,get方法访问
//二、getDeclaredFields(),递归父类
Field[] declaredFields = clazz.getDeclaredFields();
//拿到所有public
Field[] fields = clazz.getFields();
Field f = clazz.getDeclaredField("userService");
//私有访问,开启暴力
f.setAccessible(true);
f.set(userController, userService);
System.out.println(userController.getUserService());
//通过set方法注入
String fieldName = f.getName();
fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
String methodName = "set" + fieldName;
Method method = clazz.getMethod(methodName, UserService.class);
method.invoke(userController, userService);
System.out.println(userController.getUserService());
//spring容器的核心原理
//通过类模板获取controller的所有属性,遍历属性是否有Autowired注解
Stream.of(clazz.getDeclaredFields()).forEach(field -> {
String name = field.getName();
//拿到属性的注解,不为空则set依赖对象
Autowired annotation = field.getAnnotation(Autowired.class);
if (annotation != null){
field.setAccessible(true);
Class<?> type = field.getType();
try {
//spring通过beanName从容器拿到对象,注入属性
/**
spring容器流程,扩展性
底层结构:
Map<beanName, BeanDefinition> map
Map<class, BeanDefinition> map
BeanDefinitionReader读取 xml | annotation获取bean信息
BeanDefinitionRegister
实例化BeanDefinition信息到容器
可通过BeanFactoryPostProcessor增强扩展工厂
工厂BeanFactory:Object o = type.getConstructor().newInstance();
通过BeanDefinition实例化对象到容器
可通过BeanPostProcessor增强扩展Bean
实例化对象前processor扩展
初始化对象前processor扩展
初始化对象后processor扩展
Environment环境
*/
//也可以通过set方法注入
Object o = type.getConstructor().newInstance();
field.set(userController, o);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
});
}
}
Profile注解
//在dev环境下才注入
@Profile("dev")
@Configuration
public class DevConfiguration{
}
//根据不同环境读取相应的配置
java -jar -Dspring.profiles.active=test -Dserver.port=8080 xxx.class
核心接口
父子容器的关系:
从子容器中拿Bean,拿不到再从父容器里拿。子容器的Bean可以覆盖父容器的Bean。
-
BeanFactory,ioc最基础工厂,定义bean工厂的规范,主要方法有
getBean(String name)、containsBean(String name)、isSingleton(String name)、isPrototype(String name)、getType(String name)
等等。 -
ListableBeanFactory,继承BeanFactory,管理bean信息,也就是管理BeanDefinition,除了基础BeanFactory方法,还有
containsBeanDefinition(String beanName)、getBeanDefinitionNames()、getBeanNamesForType(@Nullable Class<?> type)
等等。 -
ApplicationContext,允许容器通过应用程序上下文环境创建、获取、管理bean。继承了很多接口,访问应用程序组件的Bean工厂方法,从ListableBeanFactory继承。以通用方式加载文件资源的能力,继承自ResourceLoader接口。向注册侦听器发布事件的能力,继承自ApplicationEventPublisher接口。解析消息的能力,支持国际化,继承自MessageSource接口。从父上下文继承,后代上下文中的定义总是优先级。例如,这意味着单个父上下文可以被整个web应用程序使用,而每个servlet都有自己独立于任何其他servlet的子上下文。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
-
HierarchicalBeanFactory(haɪəˈrɑːkɪkl),获取工厂的父子关系
-
xxxAware,Aware类都是调用setXXX方法获取容器组件信息注入到Bean中
-
Environment,获取环境配置文件properties/yml,解析
@NotNull不为NULL,@Nullable可为NULL。
BeanFactory和FactoryBean的区别
1.BeanFactory
BeanFactory是IOC最基本的容器,负责生产和管理bean,它为其他具体的IOC容器提供了最基本的规范,例如DefaultListableBeanFactory,
XmlBeanFactory,ApplicationContext 等具体的容器都是实现了BeanFactory,再在其基础之上附加了其他的功能。
BeanFactory源码
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
2.FactoryBean
FactoryBean是一个接口,当在IOC容器中的Bean实现了FactoryBean后,通过getBean(String BeanName)获取到的Bean对象并不是FactoryBean的实现类对象,而是这个实现类中的getObject()方法返回的对象。要想获取FactoryBean的实现类,就要getBean(&BeanName),在BeanName之前加上&。openFegin用到FactoryBean
为啥要FactoryBean?为啥要getObject()获取Bean?
可以在getObject方法写自己的逻辑,生成自定义的对象,扩展工厂生产对象。
FactoryBean源码
package org.springframework.beans.factory;
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
下面是一个应用FactoryBean的例子
<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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="student" class="com.spring.bean.Student">
<property name="name" value="zhangsan" />
</bean>
<bean id="school" class="com.spring.bean.School">
</bean>
<bean id="factoryBeanPojo" class="com.spring.bean.FactoryBeanPojo">
<property name="type" value="student" />
</bean>
</beans>
FactoryBean的实现类
import org.springframework.beans.factory.FactoryBean;
/**
* @author 作者 wangbiao
* @date 创建时间:2016年11月14日 上午11:19:31
* @parameter
* @return
*/
public class FactoryBeanPojo implements FactoryBean{
private String type;
@Override
public Object getObject() throws Exception {
if("student".equals(type)){
return new Student();
}else{
return new School();
}
}
@Override
public Class getObjectType() {
return School.class;
}
@Override
public boolean isSingleton() {
return true;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
普通的bean
/**
* @author 作者 wangbiao
* @date 创建时间:2016年11月14日 上午11:13:18
* @parameter
* @return
*/
public class School {
private String schoolName;
private String address;
private int studentNumber;
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getStudentNumber() {
return studentNumber;
}
public void setStudentNumber(int studentNumber) {
this.studentNumber = studentNumber;
}
@Override
public String toString() {
return "School [schoolName=" + schoolName + ", address=" + address
+ ", studentNumber=" + studentNumber + "]";
}
}
测试类
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.bean.FactoryBeanPojo;
/**
* @author 作者 wangbiao
* @date 创建时间:2016年11月14日 上午11:11:35
* @parameter
* @return
*/
public class FactoryBeanTest {
public static void main(String[] args){
String url = "com/spring/config/BeanConfig.xml";
ClassPathXmlApplicationContext cpxa = new ClassPathXmlApplicationContext(url);
Object school= cpxa.getBean("factoryBeanPojo");
FactoryBeanPojo factoryBeanPojo= (FactoryBeanPojo) cpxa.getBean("&factoryBeanPojo");
System.out.println(school.getClass().getName());
System.out.println(factoryBeanPojo.getClass().getName());
}
}
输出的结果:
十一月 16, 2016 10:28:24 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1e8ee5c0: startup date [Wed Nov 16 10:28:24 CST 2016]; root of context hierarchy
十一月 16, 2016 10:28:24 上午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [com/spring/config/BeanConfig.xml]
十一月 16, 2016 10:28:24 上午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@35b793ee: defining beans [student,school,factoryBeanPojo]; root of factory hierarchy
com.spring.bean.Student
com.spring.bean.FactoryBeanPojo
BeanFactory和FactoryBean的区别:
BeanFactory和FactoryBean其实没有什么比较性的,只是两者的名称特别接近,所以有时候会拿出来比较一番,BeanFactory是提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,FactoryBean可以说为IOC容器中Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,我们可以在getObject()方法中灵活配置。其实在Spring源码中有很多FactoryBean的实现类,要想深入准确的理解FactoryBean,只有去读读Spring源码了。
*Aware含义
Spring中有很多继承于aware中的接口,这些接口到底是做什么用到的。
aware,翻译过来是知道的,已感知的,意识到的,所以这些接口从字面意思应该是能感知到所有Aware前面的含义。
先举个BeanNameAware的例子,实现BeanNameAware接口,可以让该Bean感知到自身的BeanName(对应Spring容器的BeanId属性)属性, 举个例子:
-
BeanNameAware接口的定义
public interface BeanNameAware extends Aware { void setBeanName(String name); }
-
定义两个User,一个实现BeanNameAware,一个不实现。
import org.springframework.beans.factory.BeanNameAware; /** * Created by jetty on 18/1/31. */ public class User implements BeanNameAware{ private String id; private String name; private String address; public void setBeanName(String beanName) { //ID保存BeanName的值 id=beanName; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
import org.springframework.beans.factory.BeanNameAware; /** * Created by jetty on 18/1/31. */ public class User2 { private String id; private String name; private String address; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", address='" + address + '\'' + '}'; } }
-
在Spring配置文件中初始化两个对象。
<bean id="zhangsan" class="com.github.jettyrun.springinterface.demo.aware.beannameaware.User"> <property name="name" value="zhangsan"></property> <property name="address" value="火星"></property> </bean> <bean id="lisi" class="com.github.jettyrun.springinterface.demo.aware.beannameaware.User2"> <property name="name" value="lisi"></property> <property name="address" value="火星"></property> </bean>
-
main方法测试一下BeanNameAware接口所起的作用。
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application-beanaware.xml"); User user=context.getBean(User.class); System.out.println(String.format("实现了BeanNameAware接口的信息BeanId=%s,所有信息=%s",user.getId(),user.toString())); User2 user2=context.getBean(User2.class); System.out.println(String.format("未实现BeanNameAware接口的信息BeanId=%s,所有信息=%s",user2.getId(),user2.toString())); }
-
运行结果
实现了BeanNameAware接口的信息BeanId=zhangsan,所有信息=User{id='zhangsan', name='zhangsan', address='火星'} 未实现BeanNameAware接口的信息BeanId=null,所有信息=User{id='null', name='lisi', address='火星'}
能够看到,我们在实现了BeanNameAware的 User中,获取到了Spring容器中的BeanId(对应spring配置文件中的id属性),而没有实现BeanNameAware的User2,则不能获取到Spring容器中的Id属性。
所以BeanNameAware接口是为了让自身Bean能够感知到,获取到自身在Spring容器中的id属性。
同理,其他的Aware接口也是为了能够感知到自身的一些属性。
比如实现了ApplicationContextAware接口的类,能够获取到ApplicationContext,实现了BeanFactoryAware接口的类,能够获取到BeanFactory对象。
IOC源码流程
spring框架的扩展性:
-
对象实例化前添加某些功能
-
对象初始化前后添加某些功能
-
在不同的阶段发出不同的事件,完成一些功能
-
面向接口编程
简单脉络图:
-
ApplicationContext容器入口,先getEnvironment解析properties/yml等系统环境变量,System.getProperty(),返回StandardEnvironment对象,代码中可以通过SpeL表达式获取环境变量(@Value,$#{})。
-
AbstractApplicationContext的refresh方法,ioc的核心流程:
@Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 环境设置等 prepareRefresh(); // 创建Bean工厂,读取xml,注解 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 给Bean工厂设置组件 prepareBeanFactory(beanFactory); try { // 扩展BeanFactory,空函数 postProcessBeanFactory(beanFactory); // BeanFactoryPostProcessor扩展,可实例化Bean前修改BeanDefinition信息 invokeBeanFactoryPostProcessors(beanFactory); // BeanPostProcessor扩展,Bean初始化前后 registerBeanPostProcessors(beanFactory); // 国际化配置,i18n initMessageSource(); // 监听事件,指完成操作后触发某些功能,观察者模式 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // 实例初始化完成,解决循环依赖问题 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // 清空销毁 // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; }
-
创建Bean工厂,loadBeanDefinitions()方法,实现BeanDefinitionReader接口,然后读取xml、注解或者其他形式的Bean信息,解析封装成BeanDefinition对象,存放到beanDefinitionMap。
容器底层是如下的ConcurrentHashMap:
BeanDefinition对象内容,通过xml或者注解表示,Bean的信息:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
void setScope(@Nullable String scope);
@Nullable
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
void setPrimary(boolean primary);
boolean isPrimary();
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
void setRole(int role);
int getRole();
void setDescription(@Nullable String description);
@Nullable
String getDescription();
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
}
-
invokeBeanFactoryPostProcessors(beanFactory);,BeanFactoryPostProcessor扩展,可以在实例化Bean前修改BeanDefinition信息。
-
BeanFactory内部实例化bean之后,在要初始化bean对象之前,增加了一个一系列aware接口,将它的容器,以及工厂都暴露出来供使用者自由支配做扩展用,也就是可以注入到实现了aware接口的类中。
-
经过一些列容器以及容器对象的注入之后,在初始化之前,spring又增加了一个接口 beanPostProcessor,该接口是可以作用于所有创建的bean,在初始化前后,均能通过重写该接口获取bean对象进行定制操作。
-
设置国际化配置,注册事件,利用三级缓存解决循环依赖问题,利用反射,构造器实例化,注入到对应对象的属性,完成初始化功能。
-
经过实现销毁接口disposableBean结束其生命。
BeanFactoryPostProcessor扩展接口:
@FunctionalInterface
public interface BeanFactoryPostProcessor {
// 实例化前
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
BeanPostProcessor扩展接口:
public interface BeanPostProcessor {
//Bean初始化前
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
//Bean初始化后
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
Bean的生命周期
BeanFactory源码注释:
/**
* <p>Bean factory implementations should support the standard bean lifecycle interfaces
* as far as possible. The full set of initialization methods and their standard order is:
* <ol>
* <li>BeanNameAware's {@code setBeanName}
* <li>BeanClassLoaderAware's {@code setBeanClassLoader}
* <li>BeanFactoryAware's {@code setBeanFactory}
* <li>EnvironmentAware's {@code setEnvironment}
* <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
* <li>ResourceLoaderAware's {@code setResourceLoader}
* (only applicable when running in an application context)
* <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
* (only applicable when running in an application context)
* <li>MessageSourceAware's {@code setMessageSource}
* (only applicable when running in an application context)
* <li>ApplicationContextAware's {@code setApplicationContext}
* (only applicable when running in an application context)
* <li>ServletContextAware's {@code setServletContext}
* (only applicable when running in a web application context)
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
* <li>InitializingBean's {@code afterPropertiesSet}
* <li>a custom init-method definition
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
* </ol>
*
* <p>On shutdown of a bean factory, the following lifecycle methods apply:
* <ol>
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
* <li>DisposableBean's {@code destroy}
* <li>a custom destroy-method definition
* </ol>
*/
Bean的构造过程:
文字描述:
- Spring启动,查找并加载需要被Spring管理的bean,进行Bean的实例化
- Bean实例化后对将Bean的引入和值注入到Bean的属性中
- 如果Bean实现了BeanNameAware接口的话,Spring将Bean的Id传递给setBeanName()方法
- 如果Bean实现了BeanFactoryAware接口的话,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入
- 如果Bean实现了ApplicationContextAware接口的话,Spring将调用Bean的setApplicationContext()方法,将bean所在应用上下文引用传入进来。
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessBeforeInitialization()(in ne suo l z tion)方法。
- 如果Bean 实现了InitializingBean接口,Spring将调用他们的afterPropertiesSet()方法。类似的,如果bean使用init-method声明了初始化方法,该方法也会被调用
- 如果Bean实现了BeanPostProcessor接口,Spring就将调用他们的postProcessAfterInitialization()方法。
- 此时,Bean已经准备就绪,可以被应用程序使用了。他们将一直驻留在应用上下文中,直到应用上下文被销毁。
- 如果bean实现了DisposableBean接口,Spring将调用它的destory()接口方法,同样,如果bean使用了destory-method 声明销毁方法,该方法也会被调用。
Bean的作用域
Spring中的bean默认都是单例的,对于Web应用来说,Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求,引入Spring框架之后,每个Action都是单例的,那么对于Spring托管的单例Service Bean,如何保证其安全呢? **Spring的单例是基于BeanFactory也就是Spring容器的,单例Bean在此容器内只有一个,Java的单例是基于 JVM,每个 JVM 内只有一个实例。**可通过Scope指定作用域。
- singleton,单例,在Spring容器中仅存在一个Bean的实例,Bean以单例方式存在,默认值。
- prototype,多例,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new xxxBean()。
- request,每次HTTP请求创建一个新的Bean,该作用域仅适用于WebApplicationContext环境。
- session,同一个HTTP Session 共享一个Bean,不同的Session使用不同的Bean,仅适用于WebApplicationContext环境。
- 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境。