首页 > 编程语言 >Spring源码:手写Bean配置

Spring源码:手写Bean配置

时间:2024-03-22 12:33:35浏览次数:30  
标签:String Spring final Bean 源码 static new public beanDefinition

文章目录

一、背景

下面的代码,无论是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();
}

标签:String,Spring,final,Bean,源码,static,new,public,beanDefinition
From: https://blog.csdn.net/qq_36433289/article/details/135904020

相关文章

  • SpringBoot - [03] SpringBoot整合Mybatis Plus连接数据库
    原文链接:https://mp.weixin.qq.com/s/ZJTKX_gmn6ffsY7hNrspHQ 一、开发环境JDK:1.8SpringBoot:2.1.1.RELEASEMySQL:8.0.28 二、引入依赖<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId&g......
  • Spring中Bean的生命周期
    1.BeanDefinition2.构造函数在此期间,调用Bean的构造函数,实例化对象(但是还未赋值!)3.依赖注入Spring容器会将Bean的属性设置为Bean定义中指定的值。这个过程也被称为依赖注入,因为Spring容器会自动寻找并注入Bean所依赖的其他Bean。4.Aware接口用于增强Bean的功能......
  • 【附源码】Node.js毕业设计高校后勤管理系统(Express)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:在当今信息化时代,高校后勤管理作为学校日常运营的重要组成部分,承担着保障校园环境、维护学生生活和教学秩序的重要职责。随着教育体系的不断壮大,传统的人工......
  • 【附源码】Node.js毕业设计高校后勤保修系统(Express)
    本系统(程序+源码)带文档lw万字以上  文末可获取本课题的源码和程序系统程序文件列表系统的选题背景和意义选题背景:在当今信息化时代,高效、便捷的管理方式已经成为了各个领域追求的目标。对于高校来说,后勤保修工作是保障校园正常运行的重要环节。传统的高校后勤保修工作主......
  • PHP+MySQL开发组合:智慧同城便民信息小程序源码系统 带完整的安装代码包以及安装部署教
    当前,城市生活的节奏日益加快,人们对各类便民信息的需求也愈发迫切。无论是寻找家政服务、二手交易,还是发布租房、求职信息,一个高效、便捷的信息平台显得尤为重要。传统的信息发布方式往往存在信息更新不及时、查找困难等问题,无法满足现代都市人的需求。罗峰给大家分享一款智慧同......
  • 基于security-oauth2-autoconfigure实现的OAuth2迁移到更现代的解决方案,Spring Securi
    目录OAuth2资源服务器配置步骤1:添加依赖步骤2:配置资源服务器OAuth2客户端配置(可选)/**其他应用作为OAuth2客户端步骤1:添加依赖步骤2:配置OAuth2.0客户端/**应用同时作为OAuth2客户端步骤1:配置OAuth2.0客户端控制器示例结合使用OAuth2与JWT        ......
  • 源码解析丨一次慢SQL排查
    当long_query_time=1时(表info的id为主键),出现下面的慢日志,可能会让你吃惊#Time:2024-01-28T22:52:24.500491+08:00#User@Host:root[root]@[127.0.0.1]Id:8#Query_time:7.760787Lock_time:7.757456Rows_sent:0Rows_examined:0useapple;SETtimestamp=......
  • nicerefresh--自动刷新Spring中@Value的值
    nicerefresh:自动刷新Spring项目中@Value的值。@RefreshScope虽然有这个功能,但是,它在很多场景下会失效!而nicerefresh就是为了解决这一问题而产生的。用了nicerefresh,不需要加任何注解,即可自动刷新配置!官网:https://www.yuque.com/knifeblade/opensource/nicerefreshgitee:https://......
  • SpringBoot中的一些组件
    Redis引入data-redis-starter<dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-data-redis</artifactId>  <exclusions>    <!--排除lettuce依赖-->    <exclusion>......
  • 基于Springboot的瑜伽馆管理系统的设计与实现(有报告)。Javaee项目,springboot项目。
    演示视频:基于Springboot的瑜伽馆管理系统的设计与实现(有报告)。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven+Layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构......