Spring源码:手写Bean配置

一、背景

下面的代码,无论是IOC,DI,都需要创建BeanDefinition ,设置构造器、初始方法、销毁方法等,注册BeanDefinition到BeanFactory,写代码和调用还是很繁琐,很多重复代码,所以还需要进一步优化处理

public static void testRegistBean() throws Exception {
    BeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClass(ForlanA.class);
    beanDefinition.setInitMethodName("init");
    beanDefinition.setDestroyMethodName("destroy");
    List<Object> constructorArgumentValues = new ArrayList<>();
    constructorArgumentValues.add("程序员1");
    constructorArgumentValues.add(new BeanReference("forlanAA"));
    beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
    beanFactory.registerBeanDefinition("forlanA", beanDefinition);
    beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClass(ForlanAA.class);
    beanDefinition.setInitMethodName("init");
    beanDefinition.setDestroyMethodName("destroy");
    constructorArgumentValues = new ArrayList<>();
    constructorArgumentValues.add("程序员2");
    beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
    beanFactory.registerBeanDefinition("forlanAA", beanDefinition);
    ForlanA forlanA = (ForlanA) beanFactory.getBean("forlanA");
    forlanA.introduceAll();
}

public static void testRegistBeanByStaticFactoryMethod() throws Exception  {
    BeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClass(ForlanFactory.class);
    beanDefinition.setFactoryMethodName("getForlanByStaticMethod");
    List<Object> constructorArgumentValues = new ArrayList<>();
    constructorArgumentValues.add("静态工厂方法");
    constructorArgumentValues.add(15);
    beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
    beanFactory.registerBeanDefinition("forlanByStaticMethod", beanDefinition);
    Forlan forlan = (Forlan) beanFactory.getBean("forlanByStaticMethod");
    forlan.introduce0();
}

public static void testRegistBeanByFactoryMethod() throws Exception {
    BeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClass(ForlanFactory.class);
    String factoryBeanName = "forlanFactory";
    beanFactory.registerBeanDefinition(factoryBeanName, beanDefinition);
    beanDefinition = new GenericBeanDefinition();
    beanDefinition.setFactoryBeanName(factoryBeanName);
    beanDefinition.setFactoryMethodName("getForlan");
    List<Object> constructorArgumentValues = new ArrayList<>();
    constructorArgumentValues.add("工厂bean方式");
    constructorArgumentValues.add(20);
    beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
    beanFactory.registerBeanDefinition("forlan", beanDefinition);
    Forlan forlan = (Forlan) beanFactory.getBean("forlan");
    forlan.introduce0();
}

public static void testRegistComplexBean() throws Exception {
    BeanDefinition beanDefinition1 = new GenericBeanDefinition();
    beanDefinition1.setBeanClass(Forlan.class);
    beanDefinition1.setInitMethodName("init");
    beanDefinition1.setDestroyMethodName("destroy");
    List<Object> constructorArgumentValues = new ArrayList<>();
    constructorArgumentValues.add("构造注入");
    constructorArgumentValues.add(15);
    beanDefinition1.setConstructorArgumentValues(constructorArgumentValues);
    beanDefinition1.setPrimary(true);
    beanFactory.registerBeanDefinition("forlan1", beanDefinition1);

    BeanDefinition beanDefinition2 = new GenericBeanDefinition();
    beanDefinition2.setBeanClass(Forlan.class);
    beanDefinition2.setInitMethodName("init");
    beanDefinition2.setDestroyMethodName("destroy");
    List<PropertyValue> propertyValues = new ArrayList<>();
    propertyValues.add(new PropertyValue("name", "属性依赖"));
    propertyValues.add(new PropertyValue("age", 18));
    beanDefinition2.setPropertyValues(propertyValues);
    beanFactory.registerBeanDefinition("forlan2", beanDefinition2);

    // 默认读取Primary=true的Bean
    Forlan forlan = (Forlan) beanFactory.getBean(Forlan.class);
    forlan.introduce0();
}

二、解决

1、基于xml配置

思路

定义XML规范
写代码解析XML,完成Bean定义的注册

<?xml version="1.0" encoding="UTF-8"?>
<bean id="forlanA" class="cn.forlan.aop.beans.sample.ForlanA" init-method="init" destroy-method="destroy">
    <constructor-arg type="java.lang.String" value="程序员3"/>
    <constructor-arg ref="forlanAA"/>
</bean>
<bean id="forlanAA" class="cn.forlan.aop.beans.sample.ForlanAA" init-method="init" destroy-method="destroy">
    <constructor-arg type="java.lang.String" value="程序员4"/>
</bean>

在这里插入图片描述

创建一个xml解析器
在这里插入图片描述

public class XmlBeanDefinitionReader {

	private BeanDefinitionRegistry registry;

	public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
		this.registry = registry;
	}

	public void loadBeanDefinitions(String xmlFilePath) throws Exception {
		Document document = parseToDocument(xmlFilePath);
		new BeanDefinitionParserDelegate(registry).parseDocumentRegisterBeanDefinition(document);
	}

	private Document parseToDocument(String xmlFilePath) throws Exception {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document document = builder.parse(new File(xmlFilePath));
		return document;
	}
}

解析xml标签信息

// 这个类待完善
public class BeanDefinitionParserDelegate {

	public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

	public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";

	public static final String TRUE_VALUE = "true";

	public static final String FALSE_VALUE = "false";

	public static final String DEFAULT_VALUE = "default";

	public static final String DESCRIPTION_ELEMENT = "description";

	public static final String AUTOWIRE_NO_VALUE = "no";

	public static final String AUTOWIRE_BY_NAME_VALUE = "byName";

	public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";

	public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";

	public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";

	public static final String NAME_ATTRIBUTE = "name";

	public static final String BEAN_ELEMENT = "bean";

	public static final String META_ELEMENT = "meta";

	public static final String ID_ATTRIBUTE = "id";

	public static final String PARENT_ATTRIBUTE = "parent";

	public static final String CLASS_ATTRIBUTE = "class";

	public static final String ABSTRACT_ATTRIBUTE = "abstract";

	public static final String SCOPE_ATTRIBUTE = "scope";

	private static final String SINGLETON_ATTRIBUTE = "singleton";

	public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";

	public static final String AUTOWIRE_ATTRIBUTE = "autowire";

	public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";

	public static final String PRIMARY_ATTRIBUTE = "primary";

	public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";

	public static final String INIT_METHOD_ATTRIBUTE = "init-method";

	public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";

	public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";

	public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";

	public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";

	public static final String INDEX_ATTRIBUTE = "index";

	public static final String TYPE_ATTRIBUTE = "type";

	public static final String VALUE_TYPE_ATTRIBUTE = "value-type";

	public static final String KEY_TYPE_ATTRIBUTE = "key-type";

	public static final String PROPERTY_ELEMENT = "property";

	public static final String REF_ATTRIBUTE = "ref";

	public static final String VALUE_ATTRIBUTE = "value";

	public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";

	public static final String REPLACED_METHOD_ELEMENT = "replaced-method";

	public static final String REPLACER_ATTRIBUTE = "replacer";

	public static final String ARG_TYPE_ELEMENT = "arg-type";

	public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";

	public static final String REF_ELEMENT = "ref";

	public static final String IDREF_ELEMENT = "idref";

	public static final String BEAN_REF_ATTRIBUTE = "bean";

	public static final String PARENT_REF_ATTRIBUTE = "parent";

	public static final String VALUE_ELEMENT = "value";

	public static final String NULL_ELEMENT = "null";

	public static final String ARRAY_ELEMENT = "array";

	public static final String LIST_ELEMENT = "list";

	public static final String SET_ELEMENT = "set";

	public static final String MAP_ELEMENT = "map";

	public static final String ENTRY_ELEMENT = "entry";

	public static final String KEY_ELEMENT = "key";

	public static final String KEY_ATTRIBUTE = "key";

	public static final String KEY_REF_ATTRIBUTE = "key-ref";

	public static final String VALUE_REF_ATTRIBUTE = "value-ref";

	public static final String PROPS_ELEMENT = "props";

	public static final String PROP_ELEMENT = "prop";

	public static final String MERGE_ATTRIBUTE = "merge";

	public static final String QUALIFIER_ELEMENT = "qualifier";

	public static final String QUALIFIER_ATTRIBUTE_ELEMENT = "attribute";

	public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";

	public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge";

	public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";

	public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates";

	public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";

	public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";

	private BeanDefinitionRegistry registry;

	public BeanDefinitionParserDelegate(BeanDefinitionRegistry registry) {
		this.registry = registry;
	}

	public void parseDocumentRegisterBeanDefinition(Document document) throws Exception {
		NodeList beanNodes = document.getElementsByTagName(BEAN_ELEMENT);
		for (int i = 0; i < beanNodes.getLength(); i++) {
			Node beanNode = beanNodes.item(i);
			if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
				Element element = (Element) beanNode;
				GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
				String beanName = this.parseBeanDefinitionElement(element, beanDefinition);
				this.registry.registerBeanDefinition(beanName, beanDefinition);
			}
		}
	}

	private String parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition beanDefinition) throws Exception {
		// 解析id属性,也就是BeanName
		String beanName = ele.getAttribute(ID_ATTRIBUTE);
		String className = ele.getAttribute(CLASS_ATTRIBUTE);
		String initMethod = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
		String destroyMethod = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
		beanDefinition.setBeanClass(this.getClass().getClassLoader().loadClass(className));
		beanDefinition.setInitMethodName(initMethod);
		beanDefinition.setDestroyMethodName(destroyMethod);
		this.parseConstructorArgElements(ele, beanDefinition);

		NodeList constructorArgsList = ele.getElementsByTagName(CONSTRUCTOR_ARG_ELEMENT);
		List<Object> constructorArgumentValues = new ArrayList<>();
		for (int j = 0; j < constructorArgsList.getLength(); j++) {
			Element argElement = (Element) constructorArgsList.item(j);
			String argType = argElement.getAttribute("type");
			String value = argElement.getAttribute("value");
			if (StringUtils.isNotBlank(value)) {
				constructorArgumentValues.add(value);
			} else if (argElement.hasAttribute("ref")) {
				String refName = argElement.getAttribute("ref");
				constructorArgumentValues.add(new BeanReference(refName));
			}
		}
		beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
		return beanName;
	}

	private void parseConstructorArgElements(Element beanEle, BeanDefinition beanDefinition) {
		List<Object> constructorArgumentValues = new ArrayList<>();
		NodeList constructorArgsList = beanEle.getElementsByTagName(CONSTRUCTOR_ARG_ELEMENT);
		for (int i = 0; i < constructorArgsList.getLength(); i++) {
			Element argElement = (Element) constructorArgsList.item(i);
			String value = argElement.getAttribute(VALUE_ATTRIBUTE);
			if (StringUtils.isNotBlank(value)) {
				constructorArgumentValues.add(value);
			} else if (argElement.hasAttribute(REF_ATTRIBUTE)) {
				String refName = argElement.getAttribute(REF_ATTRIBUTE);
				constructorArgumentValues.add(new BeanReference(refName));
			}
			beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
		}
	}
}

2、基于注解

类似下面这种,通过注解实现AOP和DI

@Component
public class ForlanController{

    @Autowired
    private Forlan forlan;
}

思路

定义一套注解
写代码来扫描、解析注解,完成Bean定义注册

1)定义相关注解

  • @Component:标记类为Bean
  • @Scope:Bean作用域
  • @Primary:多个Bean的情况下,默认注入的Bean
  • @Bean:注册Bean对象
  • @PostConstruct:初始化方法
  • @PreDestory:销毁方法
  • @Autowired:依赖注入
  • @Value:属性依赖
  • @Qualifier:属性依赖
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Component {

	String value() default "";
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {

	String value() default BeanDefinition.SCOPE_SINGLETON;
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Primary {
}

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {

	@AliasFor("name")
	String value() default "";

	@AliasFor("value")
	String name() default "";

	String initMethod() default "";

	String destroyMethod() default "";
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PostConstruct {
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PreDestroy {
}

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	boolean required() default true;
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {

	String value();
}

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Qualifier {

	String value() default "";
}

2)扫描包下的所有被@Componment修饰的Java类,生成BeanDefinition,注册到BeanFactory

在这里插入图片描述
实现以scan为核心方法的代码,主要包括递归扫描包目录下的.class文件、根据Class对象,解析注解,转为BeanDefintion,注册到BeanFactory中,具体代码如下:

public class ClassPathBeanDefinitionScanner {

	// 当在开发时执行单元测试,测试类是另一个类目录,这里可能有点问题,其它暂时没发现问题
	private static final int classResourceAbsolutePathIndex = new File(new File(ClassPathBeanDefinitionScanner.class.getResource("/").getPath()).getAbsolutePath()).getAbsolutePath().length();

	// 匹配数字的正则表达式,目前用于把@Value的字符串转为数字
	private static final String regex = "\\#\\{(\\d+)\\}";

	private BeanDefinitionRegistry registry;

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
		this.registry = registry;
	}

	public void scan(String... basePackages) throws Exception {
		if (basePackages != null && basePackages.length > 0) {
			for (String basePackage : basePackages) {
				// 1、递归扫描包目录下的.class文件
				Set<File> classFiles = this.doScan(basePackage);
				// 2、根据Class对象,解析注解,转为BeanDefintion,注册到BeanFactory中
				this.readAndRegisterBeanDefintion(classFiles);
			}
		}
	}

	/**
	 * 扫描指定包下的所有类
	 */
	private Set<File> doScan(String basePackage) throws IOException {
		// 将包名转为路径名
		String basePackagePath = "/" + StringUtils.replace(basePackage, ".", "/");
		// 得到包对应的目录
		File rootDir = new File(this.getClass().getResource(basePackagePath).getPath());
		// 存放找到的类文件的集合
		Set<File> scanedClassFiles = new HashSet<>();
		// 扫描class文件,存到scanedClassFiles中
		this.doRetrieveClassFiles(rootDir, scanedClassFiles);
		return scanedClassFiles;
	}

	/**
	 * 递归查找指定目录下的所有类,查找规则:.class结尾。
	 */
	protected void doRetrieveClassFiles(File dir, Set<File> result) throws IOException {
		for (File file : dir.listFiles()) {
			if (file.isDirectory() && file.canRead()) {
				doRetrieveClassFiles(file, result);

			}
			if (file.getName().endsWith(".class")) {
				result.add(file);
			}
		}
	}

	private void readAndRegisterBeanDefintion(Set<File> classFiles) throws Exception {
		for (File classFile : classFiles) {
			// 得到根路径:cn.forlan.aop.beans.sample.xxx
			String className = getClassNameFromFile(classFile);
			// 加载类
			Class<?> clazz = this.getClass().getClassLoader().loadClass(className);
			// 只处理@Component注解的类
			Component component = clazz.getAnnotation(Component.class);
			if (component == null) {
				continue;
			}

			// 没有指定名字的话,则把驼峰类名作为名字
			String beanName = component.value();
			if (StringUtils.isBlank(beanName)) {
				beanName = this.generateBeanName(clazz);
			}

			GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
			beanDefinition.setBeanClass(clazz);
			// 处理Scope
			Scope scope = clazz.getAnnotation(Scope.class);
			if (scope != null) {
				beanDefinition.setScope(scope.value());
			}
			// 处理Primary
			Primary primary = clazz.getAnnotation(Primary.class);
			if (primary != null) {
				beanDefinition.setPrimary(true);
			}
			// 处理构造方法,找出加了@Autowired注解的构造方法,将这个构造方法设置到beanDefinition中
			this.handleConstructor(clazz, beanDefinition);
			// 处理方法上的注解(找出初始化、销毁、工厂方法)
			this.handleMethod(clazz, beanDefinition, beanName);
			// 处理属性依赖
			this.handlePropertyDI(clazz, beanDefinition);
			// 注册bean定义
			this.registry.registerBeanDefinition(beanName, beanDefinition);
		}
	}

	private String getClassNameFromFile(File classFile) {
		// 例如,G:\ideaProject\ceshi\forlan-spring\target\classes\cn\forlan\aop\beans\sample\Forlan.class
		String absolutePath = classFile.getAbsolutePath();
		// 例如,cn\forlan\aop\beans\sample\Forlan.class
		String classNameWithPackage = absolutePath.substring(classResourceAbsolutePathIndex + 1);
		// 例如,cn\forlan\aop\beans\sample\Forlan
		String name = classNameWithPackage.replace(".class", "");
		// 例如,cn.forlan.aop.beans.sample.Forlan
		return StringUtils.replace(name, File.separator, ".");
	}

	/**
	 * 首字母小写
	 */
	private String generateBeanName(Class<?> clazz) {
		String simpleName = clazz.getSimpleName();
		// return simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
		return Character.toLowerCase(simpleName.charAt(0)) + simpleName.substring(1);
	}

	private void  handleConstructor(Class<?> clazz, GenericBeanDefinition beanDefinition) {
		Constructor<?>[] constructors = clazz.getConstructors();
		if (constructors == null || constructors.length == 0) {
			return;
		}
		for (Constructor<?> constructor : constructors) {
			if (constructor.isAnnotationPresent(Autowired.class)) {
				beanDefinition.setConstructor(constructor);
				// 处理设置构造参数
				beanDefinition.setConstructorArgumentValues(this.handleParameter(constructor.getParameters()));
				break;
			}
		}
	}

	private List<Object> handleParameter(Parameter[] parameters) {
		List<Object> res = new ArrayList<>();
		for (Parameter parameter : parameters) {
			Value valueAnnotation = parameter.getAnnotation(Value.class);
			if (valueAnnotation != null) {
				String value = valueAnnotation.value();
				if (value.contains("#{")) {
					value = value.replaceAll(regex, "$1");
					res.add(Integer.parseInt(value));
				} else {
					res.add(value);
				}
				continue;
			}

			Qualifier qualifier = parameter.getAnnotation(Qualifier.class);
			if (qualifier != null) {
				res.add(new BeanReference(qualifier.value()));
			} else {
				res.add(new BeanReference(parameter.getType()));
			}

		}
		return res;
	}

	private void handleMethod(Class<?> clazz, GenericBeanDefinition beanDefinition, String beanName) throws Exception {
		for (Method method : clazz.getMethods()) {
			if (method.isAnnotationPresent(PostConstruct.class)) {
				beanDefinition.setInitMethodName(method.getName());
			} else if (method.isAnnotationPresent(PreDestroy.class)) {
				beanDefinition.setDestroyMethodName(method.getName());
			} else if (method.isAnnotationPresent(Bean.class)) {
				this.handleFactoryMethod(clazz, beanName, method);
			}
		}
	}

	private void handleFactoryMethod(Class<?> clazz, String beanName, Method method) throws Exception {
		BeanDefinition beanDefinition = new GenericBeanDefinition();
		if (Modifier.isStatic(method.getModifiers())) {
			beanDefinition.setBeanClass(clazz);
		} else {
			beanDefinition.setFactoryBeanName(beanName);
		}

		beanDefinition.setFactoryMethod(method);
		beanDefinition.setFactoryMethodName(method.getName());

		//处理Scope
		Scope scope = method.getAnnotation(Scope.class);
		if (scope != null) {
			beanDefinition.setScope(scope.value());
		}
		//处理Primary
		Primary primary = method.getAnnotation(Primary.class);
		if (primary != null) {
			beanDefinition.setPrimary(true);
		}

		// 处理Bean
		Bean bean = method.getAnnotation(Bean.class);
		String targetBeanName = bean.name();
		if (StringUtils.isBlank(targetBeanName)) {
			targetBeanName = method.getName();
		}
		// 设置初始化方法、销毁方法
		if (StringUtils.isNotBlank(bean.initMethod())) {
			beanDefinition.setInitMethodName(bean.initMethod());
		}
		if (StringUtils.isNotBlank(bean.destroyMethod())) {
			beanDefinition.setDestroyMethodName(bean.destroyMethod());
		}

		// 处理设置构造参数
		beanDefinition.setConstructorArgumentValues(this.handleParameter(method.getParameters()));
		// 注册BeanDefinition
		this.registry.registerBeanDefinition(targetBeanName, beanDefinition);
	}

	private void handlePropertyDI(Class<?> clazz, GenericBeanDefinition beanDefinition) {
		List<PropertyValue> propertyValues = new ArrayList<>();
		for (Field field : clazz.getDeclaredFields()) {
			if (field.isAnnotationPresent(Autowired.class)) {
				Qualifier qualifier = field.getAnnotation(Qualifier.class);
				BeanReference reference = null;
				if (qualifier != null) {
					reference = new BeanReference(qualifier.value());
				} else {
					reference = new BeanReference(field.getType());
				}
				propertyValues.add(new PropertyValue(field.getName(), reference));
			}
		}
		beanDefinition.setPropertyValues(propertyValues);
	}
}

三、优化

通过上面的实现,给用户的体验还不是很友好,搞一个门面模式,定义一个简单的统一使用界面,引入了ApplicationContext
在这里插入图片描述

定义一个上下文接口,继承BeanFactory接口

public interface ApplicationContext extends BeanFactory {
}

定义一个公共抽象上下文对象,实现ApplicationContext接口,同时提供重写BeanFactory的方法

public abstract class AbstractApplicationContext implements ApplicationContext {
	protected DefaultBeanFactory beanFactory;

	public AbstractApplicationContext() {
		super();
		this.beanFactory = new DefaultBeanFactory();
	}

	protected void refresh() throws Exception {

		// 在registerBeanDefinition方法里面已经调用了,也可以抽取到这里调用
		// beanFactory.registerTypeNameMap();

		// 注册BeanPostProcessor
		doRegisterBeanPostProcessor();
	}

	private void doRegisterBeanPostProcessor() throws Exception {
		// 从BeanFactory中得到所有用户配置的BeanPostProcessor类型的Bean实例,注册到BeanFactory
		List<BeanPostProcessor> beanPostProcessors = beanFactory.getBeansOfTypeList(BeanPostProcessor.class);
		if (CollectionUtils.isNotEmpty(beanPostProcessors)) {
			for (BeanPostProcessor bpp : beanPostProcessors) {
				beanFactory.registerBeanPostProcessor(bpp);
			}
		}
	}

	@Override
	public Object getBean(String name) throws Exception {
		return this.beanFactory.getBean(name);
	}

	@Override
	public Class<?> getType(String name) throws Exception {
		return this.beanFactory.getType(name);
	}

	@Override
	public <T> T getBean(Class<T> requiredType) throws Exception {
		return this.beanFactory.getBean(requiredType);
	}

	@Override
	public <T> Map<String, T> getBeansOfType(Class<T> type) throws Exception {
		return this.beanFactory.getBeansOfType(type);
	}

	@Override
	public <T> List<T> getBeansOfTypeList(Class<T> type) throws Exception {
		return this.beanFactory.getBeansOfTypeList(type);
	}

	@Override
	public void registerBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
		this.beanFactory.registerBeanPostProcessor(beanPostProcessor);
	}
}

实现一个关于注解的上下文对象

public class AnnotationApplicationContext extends AbstractApplicationContext {
	public AnnotationApplicationContext(String... basePackages) throws Exception {
		super();
		// 找到所有被@Componment修饰的Java类,生成BeanDefinition,注册到BeanFactory
		new ClassPathBeanDefinitionScanner((BeanDefinitionRegistry) this.beanFactory).scan(basePackages);
		super.refresh();
	}
}

实现一个关于xml配置的上下文对象

public class XmlApplicationContext extends AbstractApplicationContext {

	public XmlApplicationContext(String filePath) throws Exception {
		super();
		// 加载解析xml配置,生成BeanDefinition,注册BeanFactory
		new XmlBeanDefinitionReader((BeanDefinitionRegistry) this.beanFactory).loadBeanDefinitions(filePath);
		super.refresh();
	}
}

四、总结

通过上面的注解或xml配置,加上门面模式,现在代码就变得很简单了,如下:

1、注解

只需要在相关的类、方法、字段加上注解

@Component
public class ForlanFactory {

	@Bean
	public static Forlan getForlanByStaticMethod(@Value("静态工厂方法") String name, @Value("#{15}") Integer age) {
		return new Forlan(name, age);
	}

	@Bean
	@Primary
	public Forlan getForlan(@Value("工厂bean方式") String name, @Value("#{20}") Integer age, @Qualifier("forlanA") ForlanA forlanA) {
		return new Forlan(name, age, forlanA);
	}
}

使用的话,直接创建一个上下文对象,内部的构造方法就会自动扫描注册Bean定义信息到BeanFactory,我们就可以直接获取到相关的Bean

public static void testRegistBeanByAnnotation() throws Exception {
    ApplicationContext context = new AnnotationApplicationContext("cn.forlan.aop.beans.sample");
    ForlanA forlanA = (ForlanA) context.getBean("forlanA");
    forlanA.introduceAll();
}

public static void testRegistBeanByStaticFactoryMethodByAnnotation() throws Exception {
    ApplicationContext context = new AnnotationApplicationContext("cn.forlan.aop.beans.sample");
    Forlan forlan = (Forlan) context.getBean("getForlanByStaticMethod");
    forlan.introduce0();
}

public static void testRegistBeanByFactoryMethodByAnnotation() throws Exception {
    ApplicationContext context = new AnnotationApplicationContext("cn.forlan.aop.beans.sample");
    Forlan forlan = (Forlan) context.getBean("getForlan");
    forlan.introduce0();
}

public static void testRegistComplexBeanByAnnotation() throws Exception {
    ApplicationContext context = new AnnotationApplicationContext("cn.forlan.aop.beans.sample");
    Forlan forlan = (Forlan) context.getBean(Forlan.class);
    forlan.introduce0();
}

2、xml配置

新增forlan.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="forlanA" class="cn.forlan.aop.beans.sample.ForlanA" init-method="init" destroy-method="destroy">
        <constructor-arg type="java.lang.String" value="程序员3"/>
        <constructor-arg ref="forlanAA"/>
    </bean>

    <bean id="forlanAA" class="cn.forlan.aop.beans.sample.ForlanAA" init-method="init" destroy-method="destroy">
        <constructor-arg type="java.lang.String" value="程序员4"/>
    </bean>

</beans>

使用的话,直接创建一个上下文对象,内部的构造方法就会自动解析配置为Bean定义信息到BeanFactory,我们就可以直接获取到相关的Bean

public static void testRegistBeanByXml() throws Exception {
    ApplicationContext context = new XmlApplicationContext("G:\\ideaProject\\ceshi\\forlan-spring\\src\\main\\resources\\forlan.xml");
    ForlanA forlanA = (ForlanA) context.getBean("forlanA");
    forlanA.introduceAll();
}
  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Forlan

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值