目录
1.spring运行流程
2.Bean定义,注册,获取
BeanFactory代表了bean工厂
该接口里面有getBean(String name)方法,用来返回bean对象
public class BeanDefinition{
//bean对象名称
private String beanName;
//bean对象类型
private Class<?> beanClass;
public BeanDefinition(String beanName,Class beanClass){
this.beanName = beanName;
this.beanClass = beanClass;
}
public String getBeanName(){
return this.beanName;
}
}
单例注册接口 SingletonBeanRegistry
public interface SingletonBeanRegistry {
//返回一个注册好的bean单例对象
Object getSingleton(String beanName);
}
默认实现类DefaultSingletonBeanRegistry
public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {
//创建一个容器存放单例对象
private Map<String, Object> singletonObjects = new HashMap<>();
@Override
//通过名字查找一个单例对象返回
public Object getSingleton(String beanName) {
return singletonObjects.get(beanName);
}
//注册一个单例对象
protected void addSingleton(String beanName, Object singletonObject) {
singletonObjects.put(beanName, singletonObject);
}
}
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements BeanFactory {
@Override
//只负责返回一个bean对象
public Object getBean(String name) throws BeansException {
//去单例容器中按照name寻找bean对象
Object bean = getSingleton(name);
//如果获取bean对象不为空则直接返回
if (bean != null) {
return bean;
}
//没拿到则定义一个bean的信息类,传入名称
BeanDefinition beanDefinition = getBeanDefinition(name);
//返回创建好的对象
return createBean(name, beanDefinition);
}
//返回bean对象的定义信息
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
//创建bean对象
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;
}
public interface InstantiationStrategy {
Object instantiationStrategy(String beanName, BeanDefinition beanDefinition, Constructor ctor,Object[] args);
}
这块要求我们传入一个构造方法,在AutowireCapableBeanFactory中定义一个createInstantiation方法,通过反射拿到bean对象的构造方法集合,然后放入到实例化策略中进行实例化
protected Object createInstantiation(String beanName, BeanDefinition beanDefinition, Object[] args) {
Constructor<?> constructorToUse = null;
Class<?> beanClass = beanDefinition.getBeanClass();
//拿到所有构造器
Constructor<?>[] declaredConstructors = beanClass.getDeclaredConstructors();
for (Constructor ctor : declaredConstructors) {
if (null != args && ctor.getParameterTypes().length == args.length) {
constructorToUse = ctor;
break;
}
}
return getInstantiationStrategy.instantiationStrategy(beanName, beanDefinition, constructorToUse, args);
}
public class SimpleInstantiationStrategy implements InstantiationStrategy {
@Override
public Object instantiationStrategy(String beanName, BeanDefinition beanDefinition, Constructor ctor, Object[] args) {
Class<?> beanClass = beanDefinition.getBeanClass();
try {
if (null != ctor) {
return beanClass.getDeclaredConstructor(ctor.getParameterTypes()).newInstance(args);
} else {
return beanClass.getDeclaredConstructor().newInstance();
}
} catch (Exception e) {
throw new RuntimeException();
}
}
}
而这样bean就拥有了构造方法,但是其属性值却都还是默认值,所以还要对bean的属性值进行初始化
初始化就要将属性名和值放入到BeanDefinition中,先创建一个PropertyValue来存放单个属性的属性名和属性值,这个PropertyValue代表bean对象中的一个属性
public class PropertyValue {
private String name;
private Object value;
public PropertyValue(String name, Object value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
然后创建一个PropertyValues类,该类里定义了一个Map集合用来存放一个bean对象中的所有的PropertyValue,并且可以返回一个bean中的所有属性值
public class PropertyValues {
private final List<PropertyValue> propertyValueList = new ArrayList();
public void addPropertyValue(PropertyValue pv) {
this.propertyValueList.add(pv);
}
//返回多个属性值
public PropertyValue[] getPropertyValues() {
return propertyValueList.toArray(new PropertyValue[0]);
}
//用属性名称进行对比,找到就返回
public PropertyValue getPropertyValue(String propertyName) {
for (PropertyValue pv : propertyValueList) {
if (pv.getName().equals(propertyName)) {
return pv;
}
}
return null;
}
}
但是在spring中也会存在对其他bean对象的依赖,所以还要将bean属性值和其他属性区分开来
需要创建一个BeanReference来存放bean属性的bean名称和类型,方便到时赋值时去查找或者递归创建
public class BeanReference {
private String beanName;
private Class beanClass;
public BeanReference(String beanName) {
this.beanName = beanName;
}
public BeanReference(String beanName, Class beanClass) {
this.beanName = beanName;
this.beanClass = beanClass;
}
public String getBeanName() {
return beanName;
}
public Class getBeanClass() {
return beanClass;
}
}
这样,bean的属性基本上是定义好了,现在就要通过读取资源配置文件去创建bean了
public interface Resource{
InputStream getInputStream();
}
这个接口定义了一个返回读取到资源流的方法
然后分别用ClassPathResource,FileSystemResource,UrlResource来实现该接口,分别对类路径下文件,指定资源文件,云文件进行对应的读取和包装.
ClassPathResource:
public class ClassPathResource implements Resource {
private final String path;
private ClassLoader classLoader;
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
public ClassPathResource(String path, ClassLoader classLoader) {
Assert.assertNotNull("path must not be null", path);
this.path = path;
this.classLoader = classLoader != null ? classLoader : new ClassLoader() {
@Override
public String getName() {
return super.getName();
}
};
}
@Override
public InputStream getInputStream() throws IOException {
InputStream in = classLoader.getResourceAsStream(path);
if (in == null) {
throw new FileNotFoundException(this.path + "cannot be opened because it does not exist");
}
return in;
}
}
FileSystemResource:
public class FileSystemResource implements Resource {
private final String path;
private final File file;
public FileSystemResource(String path) {
this.path = path;
this.file = new File(path);
}
public FileSystemResource(File file) {
this.file = file;
this.path = file.getPath();
}
@Override
public InputStream getInputStream() throws IOException {
return new FileInputStream(file);
}
public String getPath() {
return path;
}
}
UrlResource:
public class UrlResource implements Resource {
private final URL url;
public UrlResource(URL url) {
Assert.assertNotNull("Url must not be null", url);
this.url = url;
}
@Override
public InputStream getInputStream() throws IOException {
URLConnection connection = this.url.openConnection();
try {
return connection.getInputStream();
} catch (IOException e) {
if (connection instanceof HttpURLConnection) {
((HttpURLConnection) connection).disconnect();
}
throw e;
}
}
}
有了这三个包装类就可以对指定的资源进行读取,但是我们一般只会放入资源地址比如classpath:spring.xml这样的路径来加载资源,所以我们需要一个ResourceLoader(资源加载器)来对我们传入的路径进行判断,决定用哪个类来进行包装和读取资源.
定义一个ResourceLoader接口,里面定义了一个类路径文件前缀,定义了一个返回资源包装的方法,然后用一个默认实现类来按照给到的资源路径来选择用哪个包装类。
ResourceLoader:
public interface ResourceLoader {
String CLASSPATH_URL_PROFIX = "classpath:";
Resource getResource(String location);
}
DefaultResourceLoader:
该默认实现通过判断是否是类路径,url路径,文件路径来对该资源路径进行资源包装,然后返回该包装进行资源的读取
public class DefaultResourceLoader implements ResourceLoader {
@Override
public Resource getResource(String location) {
Assert.assertNotNull("location must not be null", location);
if (location.startsWith(CLASSPATH_URL_PROFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PROFIX.length()));
} else {
try {
URL url = new URL(location);
return new UrlResource(url);
} catch (MalformedURLException e) {
return new FileSystemResource(location);
}
}
}
}
当我们做完上面两部分后,我们就可以放入资源路径然后读取文件了,但是只是读取到了文件,现在就要将读到的流转换成bean对象
定义一个BeanDefinitionReader接口,该接口用来读取资源文件并且将其转换为BeanDefinition注入到容器中,供ioc创建bean对象使用
接口中定义了五个方法,其中loadeBeanDefinitions用来传入资源或者资源路径进行加载。
public interface BeanDefinitionReader {
BeanDefinitionRegistry getRegistry();
ResourceLoader getResourceLoader();
void loadBeanDefinitions(String location) throws IOException, ClassNotFoundException;
void loadBeanDefinitions(Resource resource) throws IOException, ClassNotFoundException;
void loadBeanDefinitions(Resource... resource) throws IOException, ClassNotFoundException;
void loadBeanDefinitions(String[] locations) throws IOException, ClassNotFoundException;
}
首先先创建一个AbstractBeanDefinitonReader方法,获得加载所需要的ioc核心类和资源加载器
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
private final BeanDefinitionRegistry registry;
private ResourceLoader resourceLoader;
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, new DefaultResourceLoader());
}
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
this.registry = registry;
this.resourceLoader = resourceLoader;
}
@Override
public BeanDefinitionRegistry getRegistry() {
return this.registry;
}
@Override
public ResourceLoader getResourceLoader() {
return this.resourceLoader;
}
}
有了BeanDefinitionRegistry就可以将读取到的bean定义存入容器中,而ResourceLoader可以对资源路径进行包装.
接下来就是实现读取xml配置的类了,创建读取xml文件的实现类XmlBeanDefinitionReader
这个类实现了接口的三个加载资源文件的方法,通过doLoadBeanDefinition来读取出xml文件中的bean信息然后转换成BeanDefinition,并将创建好的BeanDefinition放入ioc容器。
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
super(registry, resourceLoader);
}
@Override
public void loadBeanDefinitions(String location) throws IOException, ClassNotFoundException {
InputStream inputStream = getResourceLoader().getResource(location).getInputStream();
doLoadBeanDefinition(inputStream);
}
@Override
public void loadBeanDefinitions(Resource resource) throws IOException, ClassNotFoundException {
InputStream inputStream = resource.getInputStream();
doLoadBeanDefinition(inputStream);
}
@Override
public void loadBeanDefinitions(Resource... resources) throws IOException, ClassNotFoundException {
for (Resource rc : resources) {
InputStream inputStream = rc.getInputStream();
doLoadBeanDefinition(inputStream);
}
}
@Override
public void loadBeanDefinitions(String[] locations) throws IOException, ClassNotFoundException {
for (String location : locations) {
loadBeanDefinitions(location);
}
}
protected void doLoadBeanDefinition(InputStream in) throws ClassNotFoundException {
Document doc = XmlUtil.readXML(in);
Element element = doc.getDocumentElement();
NodeList nodeList = element.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
if (!(nodeList.item(i) instanceof Element))
continue;
if (!("bean".equals(nodeList.item(i).getNodeName())))
continue;
Element bean = (Element) nodeList.item(i);
String id = bean.getAttribute("id");
String name = bean.getAttribute("name");
String className = bean.getAttribute("class");
String initMethodName = bean.getAttribute("init-method");
String destroyMethodName = bean.getAttribute("destroy-method");
Class<?> clazz = Class.forName(className);
String beanName = id != null ? id : name;
if (!StrUtil.isNotEmpty(beanName)) {
beanName = StrUtil.lowerFirst(clazz.getSimpleName());
}
BeanDefinition beanDefinition = new BeanDefinition(clazz, initMethodName, destroyMethodName);
NodeList childNodes = bean.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
if (!(childNodes.item(j) instanceof Element))
continue;
if (!("property".equals(childNodes.item(j).getNodeName())))
continue;
Element property = (Element) childNodes.item(j);
String attrName = property.getAttribute("name");
String attrValue = property.getAttribute("value");
String attrRef = property.getAttribute("ref");
Object value = StrUtil.isNotEmpty(attrValue) ? attrValue : new BeanReference(attrRef);
PropertyValue propertyValue = new PropertyValue(attrName, value);
beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
}
if (getRegistry().containsBeanDefinition(beanName)) {
throw new BeanException();
}
getRegistry().registerBeanDefinition(beanName, beanDefinition);
}
}
}
读取文件并且将BeanDefinition加载到ioc后,我们就可以创建bean对象并且使用了,但是这还是太复杂了,如果要使用还要进行这些操作
手工的创建bean工厂对象
手工读取xml文件
public class Tt {
public static void main(String[] args) throws IOException, ClassNotFoundException {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions("classpath:spring.xml");
UserService userService = (UserService) beanFactory.getBean("userService", UserService.class);
userService.queryUserInfo();
}
}
这样并不是spring想要的,所以要想办法将创建工厂和读取xml文件合并,这样只要传入路径就简单多了
ApplicationContext
在实现了基本的文件配置bean对象后,我们需要考虑的是如何让用起来更简单,如果只是我们开发使用我们知道这个类,这个方法是做什么的,该放什么值,但是如果提供给未参加开发的人使用则是灾难,这样它就要去看底层究竟是干嘛的,如果是简化版的spring还好,那如果正真spring呢?这无疑直接令人想放弃这个框架的使用,所以我们要使用上下文来定义spring的运行.
ApplicationContext接口,继承了三个BeanFactory的子接口,同时令它拥有更多功能.
ListableBeanFactory是负责beanfactory的bean查寻功能
HierarchicalBeanFactory负责bean的父类使用
ApplicationEventPublisher是负责推送事件(在spring监听器中会讲到)
public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory, ApplicationEventPublisher {
}
这表示是一个上下文功能,其实真正的方法定义在后面继承该接口的ConfigurableApplicationContext接口中.
public interface ConfigurableApplicationContext extends ApplicationContext {
void refresh() throws IOException, ClassNotFoundException;
void registerShutdownHook();
void close() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException;
ConfigurableListableBeanFactory getBeanFactory();
}
接口定义了refresh方法,用来刷新spring的容器,而getBeanFactory负责返回一个beanfactory,这个ConfigurableListableBeanFactory是继承了ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory这三个接口.
ConfigurableListableBeanFactory接口:继承AutowireCapableBeanFactory接口AutowireCapableBeanFactory接口又继承了beanfactory接口
configurableListableBeanFactory应用上下文环境可以通过bean的name或者clazz获取指定的bean
同时也能获取到BeanDefinition,并且包含一个实例化所有bean对象的方法preInstantiateSingleton()
public interface ConfigurableListableBeanFactory extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
BeanDefinition getBeanDefinition(String beanName);
void preInstantiateSingletons();
}
其中的ConfigurableBeanFactory继承了HierarchicalBeanFactory, SingletonBeanRegistry,这个类还定义了addBeanPostProcessor(添加后置处理器),addEmbeddedValueResolver(添加占位符解析器),还有一个解析器的方法.
这个接口就是负责用来管理spring的各个模块方法的,同时继承了SingletonRegistry可以注册bean对象的方法.
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {
String SCOPE_SINGLETON = "singleton";
String SCOPE_PROTOTYPE = "prototype";
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
void addEmbeddedValueResolver(StringValueResolver var1);
String resolveEmbeddedValue(String var1);
}
而AutowireCapableBeanFactory接口继承了BeanFactory用来扩展bean后置处理器的位置,定了了两个方法,这两个方法从applicationcontext中可以看到,在bean初始化的时候可以对bean进行扩展
public interface AutowireCapableBeanFactory extends BeanFactory {
Object applyBeanPostProcessorsBeforeInitialization(Object var1, String var2);
Object applyBeanPostProcessorsAfterInitialization(Object var1, String var2);
}
有了定义上下文的接口,那么就要有实现类,spring用AbstractApplicationContext来实现了该接口,并且定义了spring的运行流程,同时将抽象方法继续丢给子类来实现功能.,并且在refresh将刷新spring的上下文,在刷新时就是bean的生命流程的开始,我们可以将所有创建bean的流程.方法定义到刷新方法中,将其组合成一个完整的bean创建过程,同时也可以在其中进行扩展.
AbstractApplicationContext
/**
* 上下文抽象类
* 定义了spring的上下文
*/
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
//事件广播器在ioc容器的名字
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
//事件广播器对象
private ApplicationEventMulticaster applicationEventMulticaster;
@Override
public void refresh() throws IOException, ClassNotFoundException {
//首先创建beanFactory,并加载BeanDefinition
refreshBeanFactory();
//拿到这个beanFactory对象
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
//在实例化之前做实现的事情
invokeBeanFactoryPostProcessors(beanFactory);
//注册将要在实例化之前做的事情
registerBeanPostProcessors(beanFactory);
//提前实例化所有单例对象
beanFactory.preInstantiateSingletons();
// 初始化事件广播器
initApplicationEventMulticaster();
// 注册事件监听器
registerListeners();
// 发布容器刷新完成事件
finishRefresh();
//注册销毁钩子
registerShutdownHook();
}
//初始化广播器
private void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//获取一个简单的应用广播器,将这个广播器注册到ioc中
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
//监听器注册
private void registerListeners() {
//拿到所有的监听器
Collection<ApplicationListener> listeners = getBeanOfType(ApplicationListener.class).values();
//将监听器注册到广播器中
for (ApplicationListener<?> listener : listeners) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
}
private void finishRefresh() {
//将该application进行包装到事件上下文刷新器中
publishEvent(new ContextRefreshedEvent(this));
}
//广播器发布该指定事件
public void publishEvent(Object event) {
Assert.assertNotNull("Event must not be null", event);
Object applicationEvent;
if (event instanceof ApplicationEvent) {
this.applicationEventMulticaster.multicastEvent((ApplicationEvent) event);
}
}
protected abstract void refreshBeanFactory() throws IOException, ClassNotFoundException;
// protected abstract ConfigurableListableBeanFactory getBeanFactory();
//注册一个销毁钩子
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
@Override
public void close() {
try {
//发布容器关闭事件
publishEvent(new ContextClosedEvent(this));
((DefaultListableBeanFactory) getBeanFactory()).destroySingletons();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//在进行BeanFactoryPostProcessor查询的时候同时实例化对象进行使用
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) throws IOException {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = getBeanOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor br : beanFactoryPostProcessorMap.values()) {
br.postProcessBeanFactory(beanFactory);
}
}
//在进行BeanPostProcessor查询的时候同时实例化对象,并且将对象装入到容器中
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = getBeanOfType(BeanPostProcessor.class);
for (BeanPostProcessor br : beanPostProcessorMap.values()) {
//将找到的beanpostprocessor bean对象注册到容器中,等待使用
beanFactory.addBeanPostProcessor(br);
}
}
@Override
public Object getBean(String name) {
return getBeanFactory().getBean(name);
}
@Override
public Object getBean(String name, Object... args) {
return getBeanFactory().getBean(name, args);
}
@Override
public <T> Map<String, T> getBeanOfType(Class<T> type) {
return getBeanFactory().getBeanOfType(type);
}
@Override
public String[] getBeanDefinitionNames() {
return getBeanFactory().getBeanDefinitionNames();
}
@Override
public String[] getBeanNamesForType(Class<?> type) {
return getBeanFactory().getBeanNamesForType(type);
}
}
1.bean对象的创建流程
创建beanfactory对象,原来我们使用ioc必须要手工的去创建DefaultListableBeanFactory,然后操作beanfactory,所以我们现在需要spring自己来操作,而我们只需要传入读取xml文件的路径就行了,spring就会自动的去创建beanfactory对象,然后注册BeanDefinition,创建bean,返回bean.
定义一个抽象类,实现传下来的抽象方法用来刷新beanfactory对象,在刷新beanfactory的同时还读取xml文件将bean信息注册到spring中等待使用,并且可以返回该beanfactory.
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
private DefaultListableBeanFactory beanFactory;
@Override
protected void refreshBeanFactory() throws IOException, ClassNotFoundException {
DefaultListableBeanFactory beanFactory = createBeanFactory();
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
private DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory();
}
@Override
public ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
//读取xml配置文件,加载bean定义信息
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException, ClassNotFoundException;
}
再同时留下一个抽象方法给子类实现,用来调用XmlBeanDefinitionReader读取xml配置文件,进行bean注册.
再由一个抽象方法来实现读取xml配置文件的方法,AbstractXmlApplicationContext抽象类用来读取xml配置文件,这样就不用我们手动创建读取类然后去读取,并且该抽象类也留下了一个抽象方法,留下一个传入xml文件路径的方法.
public abstract class AbstractXmlApplicationContext extends AbstractRefreshableApplicationContext {
public AbstractXmlApplicationContext() {
}
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException, ClassNotFoundException {
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(beanFactory, this);
String[] configLocations = getConfigLocation();
if (configLocations != null) {
xmlReader.loadBeanDefinitions(configLocations);
}
}
protected abstract String[] getConfigLocation();
}
最后就是子类ClassPathXmlApplicationContext实现该方法,跟我们平时用spring一样,传入一个xml文件路径就可以将xml配置加载到spring中进行bean注册了.
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
private String[] configLocations;
public ClassPathXmlApplicationContext() {
}
public ClassPathXmlApplicationContext(String configLocation) throws IOException, ClassNotFoundException {
this(new String[]{configLocation});
}
public ClassPathXmlApplicationContext(String[] configLocations) throws IOException, ClassNotFoundException {
this.configLocations = configLocations;
refresh();
}
@Override
protected String[] getConfigLocation() {
return configLocations;
}
}
这也是设计模板的理念,自上而下的实现每个功能,从一开始的创建bean对象,读取xml文件,传入路径每一步都是一个抽象类实现该实现的功能,值得学习.
最终,我们可以返回一个beanfactory对象,又注册了BeanDefinition.
后面我们只需要通过实现ConfigurableListableBeanFactory接口的 void preInstantiateSingletons()方法,循环实例化所有单例bean对象就行了.
2.bean的扩展接口
在创建bean的时候,我们现在通过上下文实现bean的创建了,那我们现在可以在bean创建的流程中添加我们自己想添加的逻辑,我们也可以在BeanDefinition注册后对bean信息做出修改,也可以在bean实例化后,在进行初始化的时候进行自己的方法处理bean对象或操作.
首先是BeanFactoryPostProcessor接口,该接口负责定义一个方法,在BeanDefinition注册后对bean信息进行修改方法,实现了这个接口后可以自定义方法对bean的信息进行修改.
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws IOException;
}
在AbstractApplicationContext的refresh中可以看到,该方法定义在拿到BeanDefinition后,对BeanFactoryPostProcessor的实现类进行了处理
invokeBeanFactoryPostProcessors(beanFactory)
从ioc容器中拿到所有实现该接口的实现类,并且执行postProcessBeanFactory方法.
//在进行BeanFactoryPostProcessor查询的时候同时实例化对象进行使用
private void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) throws IOException {
Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap = getBeanOfType(BeanFactoryPostProcessor.class);
for (BeanFactoryPostProcessor br : beanFactoryPostProcessorMap.values()) {
br.postProcessBeanFactory(beanFactory);
}
}
既然对BeanDefinition可以进行修改,那也就可以对bean进行修改,我们通过定义BeanPostProcessor接口对bean进行初始化的前后进行前置后置操作.
BeanPostProcessor接口定义了两个方法,分别为前置执行的方法和后置执行的方法.
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName);
Object postProcessAfterInitialization(Object bean, String beanName);
}
但是该方法只在bean初始化方法中才运行,我们需要现在上下文中先将其注册到spring中,以便在执行bean初始化的时候使用,同时在AbstractBeanFactory中定义容器用来存储实现类对象,待使用时取出.
首先是注册,将在spring初始化上下文的时候将该类注册到容器中,通过getType方法拿到该接口的所有实现类对象,然后注册.
//在进行BeanPostProcessor查询的时候同时实例化对象,并且将对象装入到容器中
private void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
Map<String, BeanPostProcessor> beanPostProcessorMap = getBeanOfType(BeanPostProcessor.class);
for (BeanPostProcessor br : beanPostProcessorMap.values()) {
//将找到的beanpostprocessor bean对象注册到容器中,等待使用
beanFactory.addBeanPostProcessor(br);
}
}
其二就是在实例化对象后,执行初始化方法的时候进行使用.
bean对象创建(createInstantiation)
属性填充(applyPropertyValues)
bean初始化(initializBean)
private Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
//进行功能回调
Object wrappedBean = invokeAwareMethods(beanName, bean);
//实例化前
wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
//自定义的bean初始化方法
try {
invokeInitMethods(beanName, wrappedBean, beanDefinition);
} catch (Exception e) {
throw new BeanException("Invocation of init method of bean[" + beanName + "] failed", e);
}
//实例化后
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
return wrappedBean;
}
具体方法的实现,分别调用前置和后置的实现方法:
//前置消息处理
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(existingBean, beanName);
if (current == null)
return result;
result = current;
}
return result;
}
//初始化方法
private void invokeInitMethods(String beanName, Object wrappedBean, BeanDefinition beanDefinition) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (wrappedBean instanceof InitializingBean)
((InitializingBean) wrappedBean).afterPropertiesSet();
//拿到初始化方法的方法名
String initMethodName = beanDefinition.getInitMethodName();
//如果没有则不执行
if (StrUtil.isNotEmpty(initMethodName)) {
if (initMethodName == "") {
throw new BeanException("Could not find an init method name'" + initMethodName + "'no bean with name'" + beanName + "'");
}
Method method = beanDefinition.getBeanClass().getMethod(initMethodName);
method.invoke(wrappedBean);
}
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(existingBean, beanName);
if (current == null)
return result;
result = current;
}
return result;
}
这样就可以在bean进行初始化的时候使用bean进行操作,比如我们创建好了一个读取文件的对象,在初始化时候就进行文件读取,前置的加载文件信息.
在其中还有一个初始化方法(invokemethod),接上面话题,我加载了文件信息后要进行一些处理,比如读取文件然后将其注册到ioc中等等,这些就要在我们初始化方法中进行处理.
定义一个初始化接口,用来标记初始化实现类,同时定义一个初始化方法.
public interface InitializingBean {
void afterPropertiesSet();
}
在上面也可以看到,初始化中会验证该bean对象是否实现了初始化接口,如果实现了则直接转型后运行初始化方法.
当然,还有一种方法实现初始化方法,我们可以自己在类中定义一个初始化方法,然后在xml配置文件中声明这个初始化方法名称,这样在xml读取的时候该初始方法会被注册到BeanDefinition中,然后进行使用.
<bean id="123" class="xxx" init-method="初始化方法名"/>
既然有初始化方法,就有销毁方法,通常我们可能在spring关闭的时候会进行一些操作,比如数据库关闭连接等等.
而spring有自己的默认销毁方法,添加了一个ShutdownHook来运行销毁方法和spring的功能关闭.
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::close));
}
将定义的close()方法注册到钩子当中,如果spring关闭,则执行调用其他bean对象的销毁方法
@Override
public void close() {
try {
//发布容器关闭事件
publishEvent(new ContextClosedEvent(this));
((DefaultListableBeanFactory) getBeanFactory()).destroySingletons();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
定义在DefaultSingletonBeanRegister中的销毁方法将被调用.
//销毁所有数据
public void destroySingletons() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
Collection<DisposableBean> values = disposableBeanMap.values();
//先执行所有销毁方法
for (DisposableBean disposableBean : values) {
((DisposableBeanAdapter) disposableBean).destroy();
}
singletonObjects.clear();
disposableBeanMap.clear();
}
而实现了该销毁方法的对象将执行实现的销毁方法.
定义一个销毁接口,其中定义了一个销毁方法
public interface DisposableBean {
void destroy() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;
}
定义一个包装接口的适配器,通过该类来决定使用哪种形式来销毁bean.
/**
* 销毁方法适配器
*
*/
public class DisposableBeanAdapter implements DisposableBean {
private Object bean;
private String beanName;
private String destroyMethodName;
public DisposableBeanAdapter(Object bean, String beanName, BeanDefinition beanDefinition) {
this.bean = bean;
this.beanName = beanName;
this.destroyMethodName = beanDefinition.getDestroyMethodName();
}
@Override
public void destroy() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
if (bean instanceof DisposableBean)
((DisposableBean) bean).destroy();
if (StrUtil.isNotEmpty(this.destroyMethodName) && !(bean instanceof DisposableBean) && this.destroyMethodName.startsWith("destroy")) {
Method method = bean.getClass().getMethod(destroyMethodName);
if (method == null) {
throw new BeanException("Couldn't find a destroy method name'" + destroyMethodName + "' on bean with name '" + beanName + "'");
}
method.invoke(bean);
}
}
}
销毁方法也可以分成接口实现和xml配置实现.
public interface DisposableBean {
void destroy() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException;
}
该接口提供一个销毁方法来实现bean的销毁.
而注册销毁方法则是在bean创建的时候进行注册的,将销毁方法用销毁适配器进行打包后存入容器中.
//将使用销毁方法的bean注册到容器中
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
//非Singleton类型的bean不执行销毁方法
if (!beanDefinition.isSingleton())
return;
if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
}
}
3.回调接口
在使用spring中,有时候我们扩展spring的功能也会用到一些spring本身的方法或者功能,而如果没有对应的对象则不能进行操作,比如我想进行bean的注册,我需要一个beanfactory来使用它的方法进行注册,但是我们的扩展功能有的并不在上下文中,所以无法使用spring提供的功能,这时候就需要回调接口来实现,它会将applicationcontext返回给需要功能的类进行使用.
定义回调接口Aware,该接口中没有任何方法,实际上它像是一个标记,这样就可以被spring所感知.
创建一个applicationcontext回调接口,其中定义了一个set方法,用来对applicationcontext进行赋值.
public interface ApplicationContextAware extends Aware {
//实现此接口,既能感知到所属的 ApplicationContext
void setApplicationContext(ApplicationContext applicationContext);
}
我们可以用实现类实现该接口获得applicaitoncontext.
当然,我们在spring中也要提供回调的功能,我们可以通过创建回调类继承BeanPostProcessor接口,同时在注册回调方法时放入当前的上下文,然后在bean初始化前将进行applicationcontext功能回调.
public class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ApplicationContextAware)
((ApplicationContextAware) bean).setApplicationContext(applicationContext);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return null;
}
}
该回调接方法将在上下文中进行注册,当bean被创建后在前置方法中会执行该方法,用来赋予bean对象使用spring功能的对象(权限).
同时在进行前置方法前就进行实现功能的回调.
//将是是实现了ApplicationContextAwareProcessor 接口的bean对象将回调的对应功能赋给bean对象
private Object invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(this);
}
if (bean instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bean.getClass().getClassLoader());
}
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
}
return bean;
}
4.监听与事件
在spring中也存在着事件,同时也有监听器,而这种其实是观察者模式,什么是观察者模式?
当一个事件发布者发布事件更新的时候,其他相关该事件的监听器会收到,并且做出反应.
首先需要一个事件抽象类(ApplicationEvent)和一个监听接口(ApplicationListener).
事件抽象类:该类继承了JDK的EventObject表示是一个事件类.
其中source是事件的源数据,也就是事件本身的事务.
而我们自定义的事务要实现该抽象类.
public abstract class ApplicationEvent extends EventObject {
/**
* Constructs a prototypical Event.
*
* @param source the object on which the Event initially occurred
* @throws IllegalArgumentException if source is null
*/
public ApplicationEvent(Object source) {
super(source);
}
}
同时spring的上下文中也有spring默认的上下文事件
/**
* ApplicationContext容器事件
*
*/
public class ApplicationContextEvent extends ApplicationEvent {
/**
* Constructs a prototypical Event.
*
* @param source the object on which the Event initially occurred
* @throws IllegalArgumentException if source is null
*/
public ApplicationContextEvent(Object source) {
super(source);
}
public final ApplicationContext getApplicationContext() {
return (ApplicationContext) getSource();
}
}
该接口继承了事件类,同时定义了一个返回上下文事件源的方法。
而spring上下文中还有其他大大小小的事件,比如刷新上下文发布,spring关闭发布等等,这里列出两个例子/
spring关闭动作,用户可以继承该类实现自定义spring关闭发布事件
/**
* 关闭动作
*/
public class ContextClosedEvent extends ApplicationContextEvent {
/**
* Constructs a prototypical Event.
*
* @param source the object on which the Event initially occurred
* @throws IllegalArgumentException if source is null
*/
public ContextClosedEvent(Object source) {
super(source);
System.out.println("运行完毕,Spring关闭!");
}
}
spring上下文刷新发布事件,实现该类可以自定义刷新发布事件
/**
* 监听刷新
*
*/
public class ContextRefreshedEvent extends ApplicationContextEvent {
/**
* Constructs a prototypical Event.
*
* @param source the object on which the Event initially occurred
* @throws IllegalArgumentException if source is null
*/
public ContextRefreshedEvent(Object source) {
super(source);
System.out.println("Spring初始化成功!");
}
}
而spring也有自己实现的这些事件,同时会注册到spring中。
spring自己的刷新事件
private void finishRefresh() {
//将该application进行包装到事件上下文刷新器中
publishEvent(new ContextRefreshedEvent(this));
}
监听接口:该接口泛型中要存放一个继承了事件抽象类的事件类,表示该监听器监听该事件!!
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
同时监听接口中定义了监听方法,当监听事件发布时运行该监听方法。
现在我们有了事务和监听器,但是事务需要发布出去,同时也要添加监听器,我们需要定义一个事务管理器,用来管理监听器.
定义ApplicationEventMulticaster接口,其中提供添加/移除监听器的方法,还有广播事件的广播器.
public interface ApplicationEventMulticaster {
//添加监听器
void addApplicationListener(ApplicationListener<?> listener);
//移除监听器
void removeApplicationListener(ApplicationListener<?> listener);
//广播器 multicastEvent 最终推送时间消息也会经过这个接口方法来处理谁该接收事件。
void multicastEvent(ApplicationEvent event);
}
创建一个实现类,负责对所有相应的监听器进行广播.
AbstractApplicationEventMulticaster:实现了ApplicationEventMulticaster, BeanFactoryAware ,其中通过广播接口定义了增/删监听器的具体实现,同时通过BeanFactoryAware接口回调beanfactory给属性赋值.
public abstract class AbstractApplicationEventMulticaster implements ApplicationEventMulticaster, BeanFactoryAware {
//存放(Listener)监听器的容器
public final Set<ApplicationListener<ApplicationEvent>> applicationListeners = new LinkedHashSet<>();
private ConfigurableBeanFactory beanFactory;
public AbstractApplicationEventMulticaster() {
}
public void setBeanFactory(BeanFactory beanFactory) {
if (!(beanFactory instanceof ConfigurableBeanFactory)) {
throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
} else {
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
}
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
applicationListeners.add((ApplicationListener<ApplicationEvent>) listener);
}
@Override
public void removeApplicationListener(ApplicationListener<?> listener) {
applicationListeners.remove(listener);
}
//通过事件,返回所有该事件的的监听器
protected Collection<ApplicationListener> getApplicationListeners(ApplicationEvent event) {
LinkedList<ApplicationListener> allListeners = new LinkedList<>();
//将对应该事件的监听器放入容器,然后返回所有与该事件相关的容器
for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
if (supportsEvent(applicationListener, event)) {
allListeners.add(applicationListener);
}
}
return allListeners;
}
//监听器是否对事件感兴趣
protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
//拿到该监听器的类类型
Class<? extends ApplicationListener> listenerClass = applicationListener.getClass();
/**
* 如果是通过SimpleInstantiationStrategy实现的对象则直接返回该监听器的class对象
* 如果是通过CGlib代理的对象,则返回代理类的父类(也还是监听器的class对象)
*/
//判断如何返回这个监听器类型
Class<?> targetClass = ClassUtil.isSimlpeInstantiationStrategy(listenerClass) ? listenerClass : listenerClass.getSuperclass();
//返回表示当前对象所表示的类或接口直接实现的接口类型
//拿到当前监听器的接口类型
Type genericInterface = targetClass.getGenericInterfaces()[0];
/**
* 例如,通过targetClass.getGenericInterfaces()拿到该目标类直接实现的接口类型
* 然后通过拿到的接口类型来判断该接口的参数化类型
* 如 拿到的是Listener<? extends ApplicationEvent>
* 那么通过((ParameterizedType) genericInterface).getActualTypeArguments()[0]可以拿到一个参数化类型,就是<xxx>里面的参数类型
*
*/
//通过接口类型拿到接口的参数化类型(该接口的实现类类型,也是ApplicationEvent的类或者其子类)
Type actualTypeArgument = ((ParameterizedType) genericInterface).getActualTypeArguments()[0];
//通过拿到的参数类型返回类型的全限定类名
String className = actualTypeArgument.getTypeName();
//通过拿到的事件类名,创建事件对象
Class<?> eventClassName;
try {
eventClassName = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new BeanException("wrong event class name: " + className);
}
// 判定此 eventClassName 对象所表示的类或接口与指定的 event.getClass() 参数所表示的类或接口是否相同,或是否是其超类或超接口。
// isAssignableFrom 是用来判断子类和父类的关系的,或者接口的实现类和接口的关系的,默认所有的类的终极父类都是 Object。
//判断传入的事件,和该事件监听器关注的事件是否一致
/**
* 也就是将传入的ApplicationEvent类型的类是这个实现了该监听器的类的类或者其子类,则该监听器就是负责进行该事件监听的监听器
*/
return eventClassName.isAssignableFrom(event.getClass());
}
}
该抽象实现类不仅实现了两个增删的方法,同时还提供了判断监听器是否监听该事件的方法,和返回所有监听器的方法。而将广播事件留给了子类去实现。
默认实现的事件管理器
SimpleApplicationEventMulticaster:该类继承了事件管理器抽象类,同时实现了广播器的方法。
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
//定义一个线程池控制发布事件
private Executor taskExecutor;
public SimpleApplicationEventMulticaster() {
}
public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {
this.setBeanFactory(beanFactory);
}
public void setTaskExecutor(Executor taskExecutor) {
this.taskExecutor = taskExecutor;
}
@Override
public void multicastEvent(ApplicationEvent event) {
//获取当前线程池
Executor executor = getTaskExecutor();
//获取所有监听该事件的监听器的迭代器
Iterator var5 = this.getApplicationListeners(event).iterator();
//循环读取监听器
while (var5.hasNext()) {
//拿到监听器
ApplicationListener<?> listenter = (ApplicationListener) var5.next();
/**
* 如果当前线程池不为空,则开启一个新的线程运行该对象,否则使用当前线程运行
*/
if (executor != null) {
executor.execute(() -> {
invokeListener(listenter, event);
});
} else {
this.invokeListener(listenter, event);
}
}
}
//调用监听器运行方法
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
this.doInvokeListener(listener, event);
}
//执行监听器
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
listener.onApplicationEvent(event);
}
protected Executor getTaskExecutor() {
return this.taskExecutor;
}
}
在这个默认实现的管理器中,我们只需要调用广播器方法,同时放入要被广播的事件就可以将事件广播到对应的监听器,并且执行对应的监听方法。
而如果我们要广播一个事件到监听器,则必须要将该事件发布(推)出来。所以我们还需要定义另一个接口来实现事件的发布。
ApplicationEventPublisher:事件发布接口,该接口中定义了发布事件的方法。
/**
* ApplicationEventPublisher 是整个一个事件的发布接口,所有的事件都需要从这个接口发布出去。
*
*/
public interface ApplicationEventPublisher {
//默认实现的发布方法
default void publishEvent(ApplicationEvent event) {
this.publishEvent((Object) event);
}
void publishEvent(Object event);
}
其实在一开始的Application那边就已经说过这个接口了,因为spring上下文也需要发布事件让外面知道spring在干嘛,比如spring启动了,spring关闭了。所以Application需要继承这个接口来实现事件的发布.
在AbstractApplicationContext中有其实现方法
//广播器发布该指定事件
public void publishEvent(Object event) {
Assert.assertNotNull("Event must not be null", event);
Object applicationEvent;
if (event instanceof ApplicationEvent) {
this.applicationEventMulticaster.multicastEvent((ApplicationEvent) event);
}
}
如果该对象实现了事件接口,那么该对象就是一个事件,而运行发布方法的时候就会将该对象推到广播器中,让监听器去实现功能。
有了广播器和事件发布器,那么我们就可以完整的运行观察者模式了,但是广播器没有注册,而事件发布器已经在AbstractApplicationContext中实现了,所以我们需要首先定义一个广播器对象,然后注册一个广播器
在初始化的时候,创建一个默认实现的广播器对象,同时将它存入到ioc容器中,也方便后续使用
private ApplicationEventMulticaster applicationEventMulticaster
//初始化广播器
private void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
//获取一个简单的应用广播器,将这个广播器注册到ioc中
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
}
这样我们就拥有了一个广播器可以用来对里面的监听器发布事件更新的消息了,但是现在里面没有监听器,所以我们要注册监听器。
最后就是注册监听器了,在spring上下文中定义了注册监听器的方法。
//监听器注册
private void registerListeners() {
//拿到所有的监听器
Collection<ApplicationListener> listeners = getBeanOfType(ApplicationListener.class).values();
//将监听器注册到广播器中
for (ApplicationListener<?> listener : listeners) {
this.applicationEventMulticaster.addApplicationListener(listener);
}
}
实例化所有继承了监听器的对象,同时注册到管理器当中.
5.FactoryBean
spring中的对象分为两种,一种是单例对象,还有一种是原型对象。
单例好理解,不管获取多少次,都只返回ioc中该bean对象,而原型对象则是生产对象的bean对象,它每次返回的对象都会新创建一个对象返回(地址不同)。
如果需要创建原型对象,则需要创建bean工厂,也就是FactoryBean,该接口是一个泛型接口,泛型就是要返回的对象类型,其中有一个getObject的方法,可以返回一个对象
/**
* FactoryBean 中需要提供 3 个方法,获取对象、对象类型,以及是否是单例对象,
* 如果是单例对象依然会被放到内存中。
*/
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
如果要创建原型类只要实现这个接口就行了.
那么有了FactoryBean接口,那就需要有容器存放,不肯能将原型类型返回的对象放入到单例容器中,也不可能用单例方法去注册,所以要创建一个新的注册和存放方式,用来注册 FactoryBean.
FactoryBeanRegistrySupport:继承了默认实现的单例注册类,同时自身有存放单例FactoryBean的容器,并且提供了返回生成对象的方法,如果返回对象是单例的则放入FactoryBean的容器中进行存储,方便下次调用获取.
/**
* FactoryBeanRegistrySupport 类主要处理的就是关于 FactoryBean 此类对象的注册
* 操作,之所以放到这样一个单独的类里,就是希望做到不同领域模块下只负责各自
* 需要完成的功能,避免因为扩展导致类膨胀到难以维护。
* 同样这里也定义了缓存操作 factoryBeanObjectCache,用于存放单例类型的对象,
* 避免重复创建。在日常使用用,基本也都是创建的单例对象
* doGetObjectFromFactoryBean 是具体的获取 FactoryBean#getObject() 方法,因为既有缓存的处理也有对象的获取,所以额外提供了 getObjectFromFactoryBean进行逻辑包装,
* 这部分的操作方式是不和你日常做的业务逻辑开发非常相似。从Redis 取数据,如果为空就从数据库获取并写入 Redis
*
*/
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
private Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap();
protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
}
protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName) {
//判断是否是单例对象,不是单例对象则不存储到容器中
if (factory.isSingleton()) {
Object object = this.factoryBeanObjectCache.get(beanName);
/**
* 这个位置就将FactoryBean给替换出来了
* 取而代之的是getObject方法返回的对象
*/
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
this.factoryBeanObjectCache.put(beanName, object);
}
return object;
} else {
return doGetObjectFromFactoryBean(factory, beanName);
}
}
private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName) {
try {
return factory.getObject();
} catch (Exception e) {
throw new BeanException("FactoryBean threw exception on object[" + beanName + "] creation", e);
}
}
}
而在AbstractBeanFactory中也做了相应的改动,继承了FactoryBeanRegistrySupport,以前是直接返回bean对象的,现在则进行判断,该对象是否属于单例对象,再进行下一步操作,同时在返回对象的时候也进行判断,如果该bean实现了FactoryBean 接口则返回getObject对象,其实在spring中,如果想返回FactoryBean对象只要在类名前面加上一个&字符就行了,这里不做演示.
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
//bean对象的后置处理器容器
private List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
//存放占位字符解析器
List<StringValueResolver> embeddedValueResolvers = new LinkedList<>();
@Override
public Object getBean(String name) {
return getBean(name, null);
}
public Object getBean(String name, Object... args) {
return doGetBean(name, args);
}
protected <T> T doGetBean(final String name, final Object[] args) {
Object sharedInstance = getSingleton(name);
if (sharedInstance != null) {
// 如果是 FactoryBean,则需要调用 FactoryBean#getObject
return (T) getObjectForBeanInstance(sharedInstance, name);
}
BeanDefinition beanDefinition = getBeanDefinition(name);
Object bean = createBean(name, beanDefinition, args);
/**
* 开天辟地的创造!!!
* 首先如果我们进行bean实例化,所有的BeanFactory和FactoryBean都会被实例化
* 并且如果是单例对象都先注册到SingletonObjects容器中
* 但是!!!!
* 在返回的时候做了小小的变化
* 当如果是BeanFactory的时候实例化bean会被直接返回,而如果是FactoryBean的bean对象则要进行处理
* 首先判断是否是单例的bean对象,如果是则注册到FactoryBeanCache容器中
* 如果不是则直接获取后返回
* 这个最后要返回的bean却变成了实现FactoryBean类下的getObject方法返回的一个对象作为bean对象返回!!!!nb
*/
return (T) getObjectForBeanInstance(bean, name);
}
private Object getObjectForBeanInstance(Object beanInstance, String beanName) {
//如果不是FactoryBean则直接返回
if (!(beanInstance instanceof FactoryBean))
return beanInstance;
Object object = getCachedObjectForFactoryBean(beanName);
if (object == null) {
FactoryBean<?> factoryBean = (FactoryBean<?>) beanInstance;
object = getObjectFromFactoryBean(factoryBean, beanName);
}
return object;
}
protected abstract BeanDefinition getBeanDefinition(String beanName);
protected abstract Object createBean(String beanName, BeanDefinition beanDefinition, Object[] args);
@Override
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
Assert.assertNotNull("beanPostProcessor must not be null", beanPostProcessor);
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
}
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
@Override
public void addEmbeddedValueResolver(StringValueResolver var1) {
this.embeddedValueResolvers.add(var1);
}
//解析该占位符
@Override
public String resolveEmbeddedValue(String var1) {
String value = null;
for (StringValueResolver resolver : embeddedValueResolvers) {
value = resolver.resolveStringValue(var1);
}
return value;
}
}
这里的设计已经很好了,它在返回原型对象的时候会进行判断,如果该类是实现了FactoryBean则将原型bean替换出来,返回的其实是getObject方法,值得学习和借鉴.
到此spring的ioc的大致核心功能就结束了,下面是spring aop了.
SpringAop的功能创建
1.定义两个接口,分别为ClassFilter和MethodMatcher
ClassFilter(类过滤器)
/**
* 定义类匹配类,用于切点找到给定的接口和目标类
*专门用于检查目标类是否是一个合适的切入点
*/
public interface ClassFilter {
//判断该类是否需要aop
boolean matches(Class<?> clazz);
}
MethodMatcher(方法匹配器)
/**
* 方法匹配器,找到表达式范围内匹配下的目标类和方法。
* methodMatcher.matches(method, targetObj.getClass())
* 实例主要是检查方法是否合适以便应用切面
*
*/
public interface MethodMatcher {
boolean matches(Method method, Class<?> targetClass);
}
然后定义一个Pointcut(切入点),将上面两个接口定义到其中,用来返回两个过滤接口
/**
* 切入点接口,定义用于获取 ClassFilter、MethodMatcher 的两个类,这两个接口获取都是切点表达式提供的内容
* 切入点指的就是需要切入的类中需要切入的具体方法
*/
public interface Pointcut {
//类文件过滤
ClassFilter getClassFilter();
//方法匹配器
MethodMatcher getMethodMather();
}
创建一个AspectJExpressionPointcut(切面)类,实现上面三个接口
这个类里面包含了PointcutExpression(切面表达式),PointcutPrimitive(原始切入方法),并且重载了两个过滤方法matches,用来判断对象是否在切面表达式内.
/**
* 切面实现类
* 该类表达切面,通过容器存储了切入的方式,然后通过切入点解析器读取传入的expression,拿到该切面的切入表达式
* 同时也定义了方法用来比对目标类是否符合切入表达式来判断时候可以切入该目标
*
*/
public class AspectJExpressionPointcut implements Pointcut, ClassFile, MethodMatcher {
/**
* PointcutPrimitive原始切入点,这个类其实是一个枚举类,可以枚举所有的切入方式
* 这个容器存储的是切入的方法处理方式
* 比如set切入还是get切入
* 或者我们自定义的切入点表达式切入
*/
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet();
//默认实现是从自定义的execution位置切入
static {
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
}
//切入点表达式
private final PointcutExpression pointcutExpression;
public AspectJExpressionPointcut(String expression) {
//切入点解析器,将定义的切入方式集合和当前类的加载器放入
PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
//通过切入点解析器,对传入的切入点位置字符串进行解析,然后获得切入点表达式
pointcutExpression = pointcutParser.parsePointcutExpression(expression);
}
//判断该类是否是切点
@Override
public boolean matches(Class<?> clazz) {
return pointcutExpression.couldMatchJoinPointsInType(clazz);
}
//判断该方法是否为切点
@Override
public boolean matches(Method method, Class<?> targetClass) {
return pointcutExpression.matchesMethodExecution(method).alwaysMatches() && matches(targetClass);
}
@Override
public ClassFile getClassFile() {
return this;
}
@Override
public MethodMatcher getMethodMather() {
return this;
}
}
有了切面后,我们就可以判断一个对象是否在切面表达式里,是否需要aop功能了!!
第二步就是定义TargetObject(目标类)和MethodInterceptor(方法拦截器)
TargetSource接口:该接口负责定义目标,并且有一个默认的DefaultTargetSource类
/**
* 目标类资源
*
*/
public interface TargetSource extends TargetClassAware {
Class<?> getTargetClass();
Object getTarget();
}
MethodInterceptor:该接口定义了invoke方法,传入的对象为一个MethodInvocation(方法请求)
/**
* 方法拦截器
* 该接口用于定义拦截后的方法实现
* 实现该接口的类要重写invoke方法,用来切入业务逻辑方法
*
*/
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation reflectiveMethodInvocation) throws Throwable;
}
//方法请求器,用来返回需要进行aop的方法
public interface MethodInvocation extends Invocation {
Method getMethod();
}
其默认实现类为ReflectiveMethodInvocation,该类中等于反射目标对象的大致属性,其中就包括被代理方法,可以通过这个类拿到方法进行操作.
/**
*反射被代理对象的各个属性
*/
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
//代理对象
protected Object proxy;
//目标对象
protected final Object target;
//目标参数
protected Object[] arguments;
//目标方法
protected final Method method;
//目标类类对象
private Class<?> targetClass;
protected MethodProxy proxyMethod;
public ReflectiveMethodInvocation(Object target, Object[] arguments, Method method) {
this.target = target;
this.arguments = arguments;
this.method = method;
}
public ReflectiveMethodInvocation(Object target, Object[] arguments, Method method, MethodProxy proxyMethod) {
this.target = target;
this.arguments = arguments;
this.method = method;
this.proxyMethod = proxyMethod;
}
public Object proceed() throws Throwable {
return method.invoke(target, arguments);
}
public Object getProxy() {
return proxy;
}
public void setProxy(Object proxy) {
this.proxy = proxy;
}
public Object getTarget() {
return target;
}
public Object[] getArguments() {
return arguments;
}
public void setArguments(Object[] arguments) {
this.arguments = arguments;
}
public Method getMethod() {
return method;
}
public Class<?> getTargetClass() {
return targetClass;
}
public void setTargetClass(Class<?> targetClass) {
this.targetClass = targetClass;
}
@Override
public Object getThis() {
return this.target;
}
}
现在,我们可以找到需要aop的目标了,也拿到了目标的信息,并且可以把目标信息通过MethodInvocation传递到MethodInterceptor中对目标进行操作了,所以将这三个功能打包到一个类中,方便我们下一步的操作
这样我们就能知道是哪个目标(对象)需要进行aop功能操作,同时用MethodInterceptor代替原始方法执行拦截的功能.
这里可能说起来很拗口,举个例子如下:
public class aop{
//皮一下,hhh
int main(void){
//如果不是表达式内的对象我正常通过反射实现方法
if(!matchs(bean.class)){
method.invoke(obj,args);
}
else {
//否则执行拦截器拦截该方法,在拦截器里对该方法进行aop操作
getMethodInterceptor.invoke(MethodInvocation);
}
}
}
将上面三个功能打包到AdisedSupport中,方便在使用时进行通知
/**
* 通知依赖
* AdvisedSupport,主要是用于把代理、拦截、匹配的各项属性包装到一个类中
* 方便在 Proxy 实现类进行使用。这和你的业务开发中,包装入参是一个道理
* TargetSource,是一个目标对象,在目标对象类中提供 Object 入参属性,以及获取目标类 TargetClass 信息。
* MethodInterceptor,是一个具体拦截方法实现类,由用户自己实现 MethodInterceptor#invoke 方法,做具体的处理。
* MethodMatcher,是一个匹配方法的操作,这个对象由 AspectJExpressionPointcut提供服务。
*
*/
public class AdvisedSupport implements Adviced {
//被代理目标对象
private TargetSource targetSource;
//代理方式,默认使用JDK代理
private boolean proxyTargetClass = false;
//方法拦截器
private MethodInterceptor methodInterceptor;
//方法匹配器,其实默认就是实现类AspectJExpressionPointcut
private MethodMatcher methodMatcher;
public TargetSource getTargetSource() {
return targetSource;
}
public void setTargetSource(TargetSource targetSource) {
this.targetSource = targetSource;
}
public MethodInterceptor getMethodInterceptor() {
return methodInterceptor;
}
public void setMethodInterceptor(MethodInterceptor methodInterceptor) {
this.methodInterceptor = methodInterceptor;
}
public MethodMatcher getMethodMatcher() {
return methodMatcher;
}
public void setMethodMatcher(MethodMatcher methodMatcher) {
this.methodMatcher = methodMatcher;
}
public void setProxyTargetClass(boolean proxyTargetClass) {
this.proxyTargetClass = proxyTargetClass;
}
@Override
public boolean isProxyTargetClass() {
return this.proxyTargetClass;
}
}
第三步,如果要对方法进行aop操作,那我们就要拿到该方法,然后才能在方法前后做aop操作,所以我们将这类需要aop操作的对象就用Proxy来代理方法运行,当Proxy的方法拦截器拦截到被代理的方法后就可以进行aop操作.
当然,我们实现代理就要实现它的InvocationHandler(调用处理器),实现invoke方法,这个invoke方法就是代理类的实现方法,同时可以拿到proxy(代理对象),method(代理方法),args(传入参数),而我们要在创建代理后返回一个代理对象,这个对象才是实现了aop功能的bean对象,放入到ioc容器中使用
AopProxy接口定义了一个getProxy()方法,返回一个Object的代理对象.
而代理方法分为JDK代理和CGlib代理,分别实现如下:
JDK
/**
* 基于 JDK 实现的代理类,需要实现接口 AopProxy、InvocationHandler,这样就可
* 以把代理对象 getProxy 和反射调用方法 invoke 分开处理了。
* getProxy 方法中的是代理一个对象的操作,需要提供入参 ClassLoader、AdvisedSupport、和当前这个类 this,因为这个类提供了 invoke 方法。
* invoke 方法中主要处理匹配的方法后,使用用户自己提供的方法拦截实现,做反射调用 methodInterceptor.invoke 。
* 这里还有一个 ReflectiveMethodInvocation,其他它就是一个入参的包装信息,提供了入参对象:目标对象、方法、入参。
*
*/
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
//通知实现类
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//拿到方法匹配器,判断这个对象是否是连接点,如果运行拦截器,否则正常反射调用方法
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
//拿到方法拦截器
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
//运行拦截器的invoke方法,同时将目标参数打包传过去,方便使用
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), args, method));
}
//正常运行方法
return method.invoke(advised.getTargetSource().getTarget(), args);
}
//返回一个代理的对象
@Override
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), advised.getTargetSource().getTargetClass().getInterfaces(), this);
}
}
Cglib
/**
* CGlib代理
* 基于 Cglib 使用 Enhancer 代理的类可以在运行期间为接口使用底层 ASM 字节
* 码增强技术处理对象的代理对象生成,因此被代理类不需要实现任何接口。
* 关于扩展进去的用户拦截方法,主要是在 Enhancer#setCallback 中处理,用户自己的新增的拦截处理。这里可以看到 DynamicAdvisedInterceptor#intercept 匹配方法后做了相应的反射操作
*
*/
public class Cglib2AopProxy implements AopProxy {
//增强依赖
private final AdvisedSupport advised;
public Cglib2AopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
//增强类
Enhancer enhancer = new Enhancer();
//设置需要被代理的类和类的接口,传入类对象
enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
enhancer.setInterfaces(advised.getTargetSource().getTargetClass().getInterfaces());
//代理类方法,将需要代理的aop方法实现类传入
enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
//返回创建的代理对象
return enhancer.create();
}
//静态内部类,实现了CGlib的方法拦截器,用来拦截方法
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
//被Cglib拦截的方法,其实也就是代理类要运行的方法
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//Cglib的方法调用
CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), objects, method, methodProxy);
//如果该方法是连接点则执行aop拦截器的方法
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
return advised.getMethodInterceptor().invoke(methodInvocation);
}
//如果不是连接点方法,则执行Cglib的代理方法
return methodInvocation.proceed();
}
}
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
//初始化目标类的参数
public CglibMethodInvocation(Object target, Object[] arguments, Method method, MethodProxy proxyMethod) {
super(target, arguments, method, proxyMethod);
}
//继续实现代理类的方法
@Override
public Object proceed() throws Throwable {
return this.proxyMethod.invoke(this.target, this.arguments);
}
}
}
这样我们的aop代理对象就创建好了,同时我们需要在进行代理的时候判断使用哪个代理方式,所以创建一个ProxyFactory来选择创建代理对象.
/**
* 代理工厂
* 决定用哪个代理方式来代理对象
*
*/
public class ProxyFactory {
private AdvisedSupport advisedSupport;
//拿到增强依赖包
public ProxyFactory(AdvisedSupport advisedSupport) {
this.advisedSupport = advisedSupport;
}
//返回创建的代理对象
public Object getProxy() {
return createAopProxy().getProxy();
}
private AopProxy createAopProxy() {
//如果是代理对象则用Cglib代理,否则JDK代理
if (advisedSupport.isProxyTargetClass()) {
return new Cglib2AopProxy(advisedSupport);
}
return new JdkDynamicAopProxy(advisedSupport);
}
}
至此,我们手工创建代理对象就完成了,如下:
public class aop{
int main(void){
//创建一个通知实现类
AdvisedSupport sp = new AdvisedSupport();
//对通知实现类进行装配
//设置目标对象
sp.setTargetSource(new DefaultTargetSource(xxx));
//设置拦截方法
sp.setMethodInterceptor(new UserImpMethodInterceptor());
//设置类/方法匹配器
sp.setMethodMatcher(new AspectJExpressionPointcut(expression));
//将装配好的对象入到ProxyFactory中,拿到代理对象工厂
ProxyFactory proxyFactory = new ProxyFactory(sp);
//生成aop代理对象
Object bean = proxyFactory.getProxy();
}
}
在进行代理对象方法调用的时候就会用方法匹配器判断该方法是否属于切点,如果是则执行用户自定义的拦截器方法,否则正常执行.
现在可以创建代理对象了,也可以判断是否进行aop操作,那么就要将手工的方式改写到spring框架中,融入bean的生命周期里,并且可以像spring那样进行前置通知(Before),后置通知(After),环绕通知(Around),异常通知(Throw).
首先要进行不同时间段的通知(增强),定义一个Advice接口,该接口返回该类或者子类
public interface Advice {
Advice getAdvice();
}
BeforeAdvice(前置通知),还有子接口MethodBeforeAdvice
public interface BeforeAdvice extends Advice {
}
/**
* 前置通知(增强)
* 在 Spring 框架中,Advice 都是通过方法拦截器 MethodInterceptor 实现的。环绕 Advice 类似一个拦截器的链路,Before Advice、After Advice等
* 不过暂时我们需要那么多就只定义了一个 MethodBeforeAdvice 的接口定义
*
*/
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, Object target) throws Throwable;
}
然后用户实现该接口,实现before该方法,定义前置的操作
public class UserServiceBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) {
System.out.println("拦截方法:" + method.getName());
}
@Override
public Advice getAdvice() {
return this;
}
}
这里我们就完成了用户自定义的前置方法.
既然有了前置的方法,就要有前置的拦截器,在方法前方进行拦截并执行该前置方法,所以我们需要创建一个MethodBeforeAdviceInterceptor类来实现MethodInterceptor,而不是由用户去实现创建拦截器,这个拦截器默认在代理方法前置的执行前置方法.
/**
* MethodBeforeAdviceInterceptor 实现了 MethodInterceptor 接口,在 invoke方法中调用 advice 中的 before 方法,传入对应的参数信息。
* 而这个 advice.before 则是用于自己实现 MethodBeforeAdvice 接口后做的相应处
* 理。其实可以看到具体的 MethodInterceptor 实现类,其实和我们之前做的测试是一样的,只不过现在交给了 Spring 来处理
*/
public class MethodBeforeAdviceInterceptor implements MethodInterceptor {
//前置增强方式
private MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor() {
}
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
//在执行目标方法前执行增强
this.advice.before(methodInvocation.getMethod(), methodInvocation.getArguments(), methodInvocation.getThis());
return methodInvocation.proceed();
}
@Override
public Advice getAdvice() {
return null;
}
}
以上就是通知时间段的处理,我们可以在任何时间段进行aop操作,同时其他几个也可以类似这样的方法进行开发,就不一一演示了.
最后,需要将该aop功能融入到bean的生命周期中,可能实现起来比较费事,暂时提供一个解决思路
定义一个Advisor接口,该接口定义了一个getAdvice的方法,可以返回一个增强类
public interface Advisor {
/**
* 返回此切面的增强部分,一个增强部分可能是:
* 一个接口
* 一个前置增强
* 一个后置增强
* 一个异常增强
* 等
*
* @return 返回一个增强方式
*/
Advice getAdvice();
}
定义一个PointcutAdvisor继承该接口
/**
* Advisor 承担了 Pointcut 和 Advice 的组合,Pointcut 用于获取 JoinPoint(连接点),而 Advice 决定了 JoinPoint 执行什么操作(执行的时间)。
*
*/
public interface PointcutAdvisor extends Advisor {
//返回当前访问者的切点
Pointcut getPointcut();
}
创建一个AspectJExpressionPointcutAdvisor类,实现PointcutAdvisor接口,该类对切面和增强类做了封装
/**
* 切面表达式和增强方法包装类
* AspectJExpressionPointcutAdvisor 实现了 PointcutAdvisor 接口
* 把切面pointcut、拦截(增强)方法 advice 和具体的拦截表达式包装在一起。
* 这样就可以在 xml的配置中定义一个 pointcutAdvisor 切面拦截器了。
*
*/
public class AspectJExpressionPointcutAdvisor implements PointcutAdvisor {
//切面
private AspectJExpressionPointcut pointcut;
//具体的增强方法
private Advice advice;
//表达式
private String expression;
public AspectJExpressionPointcutAdvisor() {
}
public AspectJExpressionPointcutAdvisor(String expression) {
this.expression = expression;
}
@Override
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
//返回一个切面对象
@Override
public Pointcut getPointcut() {
if (this.pointcut == null) {
this.pointcut = new AspectJExpressionPointcut(expression);
}
return this.pointcut;
}
}
进行了包装后,我们可以通过这个类拿到切面和增强方法,就可以对代理对象的具体方法进行Before,After等等的位置切入了.
最后我们只需要将aop代理对象融入到spring的bean生命周期中,并且通过读取xml配置文件来配置代理对象和拦截器,这里只提供一个思路.
创建一个DefaultAdvisorAutoProxyCreator类,实现InstantiationAwareBeanPostProcessor和BeanFactory接口,其中InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor接口,这样就可以在bean实例化前后对bean进行操作了,其实跟FactoryBean的操作类似,我们可以在初始化后进行对目标bean的拦截,并且用代理对象替换它,也可以在初始化前对该对象进行拦截,具体的可以自己实现.
而拿到BeanFactory的回调接口可以方便我们拿到beanfactory对象,让我们可以从ioc容器中拿到我们所有的切面和增强类的封装类(AspectJExpressionPointcutAdvisor),这样我们就可以循环读取该类并且判断每个切面表达式是否包含该bean对象,如果包含则开始创建AdvisedSupport开始组装代理信息,通过拿到的bean.class对象反射获取需要的属性,放入到TargetSource中,组装完毕后放入到ProxyFactory中生成代理工厂,然后通过代理工厂返回一个代理对象,至此,我们的aop就完美的融入到了ioc中.
/**
* 融入 Bean 生命周期的自动代理创建者
* 这个 DefaultAdvisorAutoProxyCreator 类的主要核心实现在于
* postProcessBeforeInstantiation 方法中,从通过 beanFactory.getBeanOfType 获取 AspectJExpressionPointcutAdvisor 开始。
* 获取了 advisors 以后就可以遍历相应的 AspectJExpressionPointcutAdvisor 填充对
* 应的属性信息,包括:目标对象、拦截方法、匹配器,之后返回代理对象即可。
* 那么现在调用方获取到的这个 Bean 对象就是一个已经被切面注入的对象了,当调
* 用方法的时候,则会被按需拦截,处理用户需要的信息。
*
*/
public class DefaultAdvisorAutoProxyCreator implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private DefaultListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (DefaultListableBeanFactory) beanFactory;
}
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
//首先判断该bean是否是Advice或者Pointcut的实现类,如果是则直接返回
if (isInfrastructureClass(beanClass)) return null;
//如果是则拿到所有AspectJExpressionPointcutAdvisor,拿到所有的切面包装对象
Collection<AspectJExpressionPointcutAdvisor> advisors = beanFactory.getBeanOfType(AspectJExpressionPointcutAdvisor.class).values();
for (AspectJExpressionPointcutAdvisor advisor : advisors) {
//拿到ClassFilter类过滤器对象
ClassFile classFile = advisor.getPointcut().getClassFile();
//判断这个切面包装类是否对应该bean对象,如果不是则返回
if (!classFile.matches(beanClass)) continue;
//创建一个整合依赖包
AdvisedSupport advisedSupport = new AdvisedSupport();
TargetSource targetSource = null;
//通过反射创建一个目标对象
try {
targetSource = new DefaultTargetSource(beanClass.getDeclaredConstructor().newInstance());
} catch (Exception e) {
e.printStackTrace();
}
//组装代理信息
advisedSupport.setTargetSource(targetSource);
advisedSupport.setMethodInterceptor((MethodInterceptor) advisor.getAdvice());
advisedSupport.setMethodMatcher(advisor.getPointcut().getMethodMather());
advisedSupport.setProxyTargetClass(false);
//用代理工厂决定用哪个方式进行代理
return new ProxyFactory(advisedSupport);
}
//否则返回接口的默认为null
return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) {
return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
}
public boolean isInfrastructureClass(Class<?> beanClass) {
boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass);
if (retVal) {
System.out.println("该类实现Advice 或 Pointcut 或 Advisor: " + beanClass.getSimpleName());
}
return retVal;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
Spring注解功能
在我们实现了spring的两大核心体系ioc和aop后,我们就可以去添加其他的辅助功能了,现在我们可以使用xml配置文件来配置spring了,但是我们还是觉得xml有些繁琐,至此,我们会按照spring同样具有的注解功能继续进行扩展,同时更加具体的了解bean的生命周期.
最基础的就是@Component和@Scope,@Component可以让spring知道这是一个bean对象,以往通过xml需要配置id和class,而现在只需要在类上面加入该注解就可以让ioc自己去创建,同时@Scope可以指定该类是单例的还是原型的.
@Component
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
String value() default "";
}
@Scope
@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
String value() default "singleton";
}
现在我们有两个注解了,但是如果要ioc能去识别,我们需要将注解进行解析和扫描还要融入bean的生命周期.
首先我们需要先扫描,spring框架中通常在xml中基础配置
<context:component-scan base-package="demo02.anno"/>
通过base-package来找到指定的包,并且扫描下面的class文件,将读取到的class文件上的注解进行解析,并且将有@Component注解的类注册到ioc中.
所以在XmlBeanDefinitionReader中我们需要将解析包扫描放到第一步,先进行注解类的注册,然后再进行xml配置的bean注册.
{
Document doc = XmlUtil.readXML(in);
Element element = doc.getDocumentElement();
NodeList nodeList = element.getChildNodes();
//进行注解扫描器寻找,找到则进行注解注册
for (int c = 0; c < nodeList.getLength(); c++) {
if (!(nodeList.item(c) instanceof Element))
continue;
if (!("component-scan".equals(nodeList.item(c).getNodeName())))
continue;
Element componentScan = (Element) nodeList.item(c);
String basePackage = componentScan.getAttribute("base-package");
if (!StrUtil.isNotEmpty(basePackage)) {
throw new BeanException("The value of base-package must not be null or empty");
}
scanPackage(basePackage);
}
//正常的xml配置读取...
}
//调用包扫描器,扫描包并且注册beanDefinition
private void scanPackage(String scanPath) {
ClassPathBeanDefinitionScanner componentScan = new ClassPathBeanDefinitionScanner(this.getRegistry());
componentScan.doScan(scanPath);
}
这样我们就可以从xml配置中读取我们需要扫描的包名,剩下的就是对指定包扫描进行类解析,上面有个scanPackage方法,传入了一个包名,该方法中创建了一个扫描器和解析器,下面有讲到.
现在我们需要一个扫描器负责找到所有该包下面的类,并且将带有@Component注解的类注册到ioc中,ClassPathScanningCandidataComponentProvider这个类就是一个Component注解扫描器,该类中的findCandidateComponents方法就是负责去寻找符合要求的类,然后将他装入集合中准备注册.
/**
* 对象扫描装配器
*
*/
public class ClassPathScanningCandidateComponentProvider {
//找到带有注解的类,并且注册其信息
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
LinkedHashSet<BeanDefinition> beanDefinitionSet = new LinkedHashSet<>();
Class[] classes = ClassUtil.scanPackageByAnnotation(basePackage, Component.class);
for (Class<?> aClass : classes) {
beanDefinitionSet.add(new BeanDefinition(aClass));
}
return beanDefinitionSet;
}
}
有了扫描器,但是这只是单个的包扫描,我们或许会扫描多个不同的包,并且还需要注册到ioc中,并且还要进行@Scope注解的解析,所以还需要一个ClassPathBeanDefinitionScanner将扫描到的对象进行解析然后创建BeanDefinition注册到ioc中.
ClassPathBeanDefinitionScanner
/**
* 注解类注册器
* 将BeanDefinition注册到ioc中
*
* @author 秦杨
* @version 1.0
*/
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
private BeanDefinitionRegistry registry;
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this.registry = registry;
}
public void doScan(String... basePackages) {
for (String basePackage : basePackages) {
//通过find方法找到需要注册的bean类
Set<BeanDefinition> components = this.findCandidateComponents(basePackage);
//拿到beanDefinition
for (BeanDefinition beanDefinition : components) {
//解析作用域
String beanScope = resolveBeanScope(beanDefinition);
//如果不是空的则直接设置值
if (StrUtil.isNotEmpty(beanScope)) {
beanDefinition.setScope(beanScope);
}
registry.registerBeanDefinition(determineBeanName(beanDefinition), beanDefinition);
}
}
}
//解析bean对象作用域
private String resolveBeanScope(BeanDefinition beanDefinition) {
Class<?> beanClass = beanDefinition.getBeanClass();
Scope scope = beanClass.getAnnotation(Scope.class);
return scope.value();
}
//创建beanName
private String determineBeanName(BeanDefinition beanDefinition) {
Class<?> beanClass = beanDefinition.getBeanClass();
Component component = beanClass.getAnnotation(Component.class);
String beanName = component.value();
//如果有名字就直接返回bean名字,没有则默认类名首字母小写
if (beanName != null) {
return beanName;
}
return StrUtil.lowerFirst(beanClass.getSimpleName());
}
}
这样我们的Component类就可以被注册到ioc中,成为bean对象,其他的像@Service,@Controller等也是同理,就不一一列举了.
Spring依赖注入
通过包扫描,我们可以对类进行注解创建bean对象,既然可以注解创建bean对象了,那么类中的属性也应该可以使用注解进行注入比如我们经常使用的@Value,@Autowire,一个是对基础属性值进行注入,而@Autowire是对引用类型进行注解.
@Value
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Value {
String value() default "";
}
@Autowire
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
public @interface Autowire {
}
这类的注解不像包扫描那样,这属于字段赋值,不应该在bean的实例化里,而应该在实例化后,属性填充之前,所以我们可以通过BeanPostProcessor在bean的生命周期中进行扩展,在注册bean的时候将我们扫描属性注解的功能注册,并且在bean实例化后进行扫描注入进去.
创建一个InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor,因为我们要区分这两个接口的作用,并且该接口要有自己独特的方法.
我们将实现这个接口,并且重写它的postAfterInstantion方法,对bean进行属性注入.
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
return null;
}
default boolean postProcessAfterInstantiation(Object bean, String beanName) {
return true;
}
default PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) {
return pvs;
}
default Object getEarlyBeanReference(String beanName, Object bean) {
return bean;
}
;
}
创建一个AutowiredAnnotationBeanPostProcessor类,实现InstantiationAwareBeanPostProcessor和BeanFactoryAware,这样可以在该类中使用benafactory的功能了.
/**
* 注解后置处理器
* 该类实现了InstantiationAwareBeanPostProcessor,该类将在进行属性填充前对属性进行注解检查
* 同时通过读到的注解信息进行相应的操作
*
*/
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) {
Class<?> beanClass = bean.getClass();
Field[] fields = beanClass.getDeclaredFields();
//读取每个字段上的Value注解
for (Field field : fields) {
Value attrValue = field.getAnnotation(Value.class);
if (attrValue == null) continue;
String value = attrValue.value();
//拿到解析到了value值
value = beanFactory.resolveEmbeddedValue(value);
BeanUtil.setFieldValueForName(field.getName(), value, bean, new BeanDefinition(beanClass));
}
//读取每个字段上的Autowire
for (Field field : fields) {
Autowire attrAutowire = field.getAnnotation(Autowire.class);
if (attrAutowire == null) continue;
Class<?> thisClassType = field.getType();
Object dependentBean = beanFactory.getBean(StrUtil.lowerFirst(thisClassType.getSimpleName()));
BeanUtil.setFieldValueForType(dependentBean, bean, new BeanDefinition(beanClass), thisClassType.getSimpleName());
}
return pvs;
}
}
在该类的postProcessPropertyValues中,我们对bean字段的注解进行扫描匹配,然后对相应的值进行提去注入.
最后我们只需要将功能放入到AbstractAutowireCapableBeanFactory中,然后插入到bean的创建中就行了
在AbstractAutowireCapableBeanFactory中创建一个applyBeanPostProcessorsBeforeApplyingPropertyValues方法,该方法里负责进行属性注入
调用实现了InstantiationAwareBeanProcessor的类,使用其方法进行注入.
//在填充bean属性之前对bean属性进行更新
public void applyBeanPostProcessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
List<BeanPostProcessor> beanPostProcessors = getBeanPostProcessors();
//读取所有后置处理器,筛选出继承InstantiationAwareBeanPostProcessor的类,将bean转换
//虽然代理类也有,但是未重写postPropertyValues方法
for (BeanPostProcessor processor : beanPostProcessors) {
if (processor instanceof InstantiationAwareBeanPostProcessor) {
PropertyValues values = ((InstantiationAwareBeanPostProcessor) processor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName);
if (values != null) {
for (PropertyValue property : values.getPropertyValues()) {
beanDefinition.getPropertyValues().addPropertyValue(property);
}
}
}
}
}
融入bean生命周期
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition, Object[] args) {
Object bean = null;
try {
bean = createInstantiation(beanName, beanDefinition, args);
//如果对象是单例对象则处理循环依赖,将实例化后的半成品对象放入工厂提前暴露出来
if (beanDefinition.isSingleton()) {
Object finalBean = bean;
//将一个返回半成品bean对象的getEarlyBeanReference方法放入到SingletonBeanFactory中,然后在需要的时候可以返回一个半成品bean对象
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, beanDefinition, finalBean));
}
//实例化后进行判断
boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
if (!continueWithPropertyPopulation) {
return bean;
}
//在进行属性填充之前对该bean上的注解信息进行扫描,然后赋值
applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
//进行xml属性填充
applyPropertyValues(beanName, beanDefinition, bean);
//进行执行Bean的前后的BeanPostProcessor处理和初始化方法的执行
bean = initializeBean(beanName, bean, beanDefinition);
其实这里是有读取PropertyValue的一个动作,我们也可以把要注入的值放入到里面,然后在接下来的属性填充中匹配注入.
占位符处理
在配置xml中和@Value注解中,有时候会使用到占位符,通过外部配置文件比如properties文件等对程序中的bean进行字段的配置,所以现在要实现这个功能,其实还是围绕着bean的生命周期进行的,我们在进行注入时将用配置文件中的数据对占位符进行替换.
首先讲xml中的占位符替换,xml中替换其实只需要在注册了BeanDefinition后执行BeanFactoryPostProcessor的时候对PropertyValue进行修改就可以了,我们创建一个PropertyPlaceholderConfigurer用来处理占位符,同时该类要继承BeanFactoryPostProcessor
/**
* 属性占位符配置器
* 可以找到占位符,然后查找properties配置文件中的值进行替换
* 依赖于 BeanFactoryPostProcessor 在 Bean 生命周期的属性,可以在 Bean 对象
* 实例化之前,改变属性信息。所以这里通过实现 BeanFactoryPostProcessor 接
* 口,完成对配置文件的加载以及摘取占位符中的在属性文件里的配置。
* 这样就可以把提取到的配置信息放置到属性配置中了,
*
* @author 秦杨
* @version 1.0
*/
public class PropertyPlaceholderConfigurer implements BeanFactoryPostProcessor {
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
//properties文件路径
private String location;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws IOException {
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource(location);
Properties properties = new Properties();
//读取properties配置文件
properties.load(resource.getInputStream());
//将占位符解析器放入ioc中,方便后面使用
StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(properties);
beanFactory.addEmbeddedValueResolver(valueResolver);
//拿到所有的BeanDefinition名字
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
for (String beanName : beanDefinitionNames) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
//拿到该bean的所有属性
PropertyValues propertyValues = beanDefinition.getPropertyValues();
//循环读取属性
for (PropertyValue prValue : propertyValues.getPropertyValues()) {
//如果值不是String类型的值,则直接返回
if (!(prValue.getValue() instanceof String)) continue;
String fieldName = prValue.getName();
String fieldValue = (String) prValue.getValue();
//拿到开头和结尾的下标
int startIndex = fieldValue.indexOf(DEFAULT_PLACEHOLDER_PREFIX);
int lastIndex = fieldValue.lastIndexOf(DEFAULT_PLACEHOLDER_SUFFIX);
//如果没有${,或者}占位符号,或为空,或者符号不正确则直接返回
if (startIndex <= -1 || lastIndex <= -1 || lastIndex <= startIndex) continue;
//将占位符去掉,拿到值的名称
String plaValue = fieldValue.substring(startIndex + 2, lastIndex);
//在配置文件中拿值
String value = properties.getProperty(plaValue);
propertyValues.addPropertyValue(new PropertyValue(fieldName, value));
}
}
}
public void setLocation(String location) {
this.location = location;
}
//一个内部类,用来解析占位符的
private class PlaceholderResolvingStringValueResolver implements StringValueResolver {
private Properties properties;
public PlaceholderResolvingStringValueResolver(Properties properties) {
this.properties = properties;
}
@Override
public String resolveStringValue(String strVal) {
strVal = strVal.substring(strVal.indexOf(DEFAULT_PLACEHOLDER_PREFIX) + 2, strVal.lastIndexOf(DEFAULT_PLACEHOLDER_SUFFIX));
return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);
}
}
protected String resolvePlaceholder(String placeholder, Properties props) {
return props.getProperty(placeholder);
}
}
而xml中的占位符就可以这样处理,但是@Value中的字段却不可以,因为这是在bean的实例化之前就进行了属性的修改,而注解要等到bean实例化后才能进行读取,不可能再本末倒置去使用这个扫描器,所以我们需要创建一个解析器用来解析注解的占位符.
需要创建一个StringValueResolver
public interface StringValueResolver {
String resolveStringValue(String value);
}
该接口定义了一个解析的方法,同时返回解析到值的key.
同时创建一个实现该接口的解析类,也是上面说过的用来处理占位符的扫描器的内部类
//一个内部类,用来解析占位符的
private class PlaceholderResolvingStringValueResolver implements StringValueResolver {
private Properties properties;
public PlaceholderResolvingStringValueResolver(Properties properties) {
this.properties = properties;
}
@Override
public String resolveStringValue(String strVal) {
strVal = strVal.substring(strVal.indexOf(DEFAULT_PLACEHOLDER_PREFIX) + 2, strVal.lastIndexOf(DEFAULT_PLACEHOLDER_SUFFIX));
return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);
}
}
protected String resolvePlaceholder(String placeholder, Properties props) {
return props.getProperty(placeholder);
}
}
这个占位符解析器会存放读取到的properties值,同时具有一个解析方法resolvePlaceholder(strVal, properties),可以解析占位符.
在扫描器加载好properties文件后会创建该解析器,并且存放到AbstractBeanFactory中,然后在实现一个解析方法,从容器中取出解析器对占位符进行解析
//解析该占位符
@Override
public String resolveEmbeddedValue(String var1) {
String value = null;
for (StringValueResolver resolver : embeddedValueResolvers) {
value = resolver.resolveStringValue(var1);
}
return value;
}
然后就拿到值进行注入.
至此spring的大致基础功能就学到这了,如果后面学到更多关于spring的将会继续更新.