精华内容
下载资源
问答
  • 1. 构造函数参数依赖的例子 @Component public class BeanA { // 省略实现 // ... } @Component public class BeanB { BeanA a; // 注意,这里可以不使用 @AutoWired 等注解就会导致Spring的依赖注入 ...

    1. 构造函数参数依赖的例子

    
    @Component
    public class BeanA {
        // 省略实现
        // ...     
    }
    
    @Component
    public class BeanB {
        BeanA a;
    
        // 注意,这里可以不使用 @AutoWired 等注解就会导致Spring的依赖注入
        public BeanB(BeanA a) {
            this.a = a;
        }
    }
    
    

    2. 构造函数参数依赖解析过程分析

    在该例子中,当从容器首次获取beanB时,会导致beanB的实例化,该实例化会调用类BeanB的构造函数BeanB(BeanA a),进而会导致beanA的实例化。该动作发生的位置如下 :

    	// AbstractAutowireCapableBeanFactory 类代码片段
        
    	/**
    	 * 根据指定的bean定义 mbd 创建指定名称为 beanName 的 bean
    	 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
    	 * factory method, constructor autowiring, or simple instantiation.
    	 * @param beanName the name of the bean
    	 * @param mbd the bean definition for the bean 
    	 * @param args explicit arguments to use for constructor or factory method invocation 通常为空
    	 * @return a BeanWrapper for the new instance
    	 * @see #obtainFromSupplier
    	 * @see #instantiateUsingFactoryMethod
    	 * @see #autowireConstructor
    	 * @see #instantiateBean
    	 */
    	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, 
    		@Nullable Object[] args) {
    		// Make sure bean class is actually resolved at this point.
            // 确保在这里先获取 bean class
    		Class<?> beanClass = resolveBeanClass(mbd, beanName);
    
    		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) 
    			&& !mbd.isNonPublicAccessAllowed()) {
            // beanClass 已经确定,但是没有使用 public 修饰,不允许 public 访问,
            // 则抛出异常 BeanCreationException
    			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
    			"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    		}
    
    		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    		if (instanceSupplier != null) {
            // 目标 bean 由 instanceSupplier 提供的情况
    			return obtainFromSupplier(instanceSupplier, beanName);
    		}
    
    		if (mbd.getFactoryMethodName() != null) {
             // 目标 bean 由 factory method 提供的情况
    			return instantiateUsingFactoryMethod(beanName, mbd, args);
    		}
    
    		// Shortcut when re-creating the same bean...
    		// 重复创建同一个bean时的快捷处理 
    		boolean resolved = false;
    		boolean autowireNecessary = false;
    		if (args == null) {
    			synchronized (mbd.constructorArgumentLock) {
    				if (mbd.resolvedConstructorOrFactoryMethod != null) {
    					resolved = true;
    					autowireNecessary = mbd.constructorArgumentsResolved;
    				}
    			}
    		}
    		if (resolved) {
    			if (autowireNecessary) {
    				// 使用构造函数自动装配方式实例化bean
    				// 构造函数的参数会被作为依赖被解析和注入
    				return autowireConstructor(beanName, mbd, null, null);
    			}
    			else {
    				// 使用缺省构造函数实例化bean
    				// 缺省构造函数也就是一般所说的无参构造函数
    				return instantiateBean(beanName, mbd);
    			}
    		}
    
    		// Candidate constructors for autowiring?
    		// 使用 BeanPostProcessors 决定使用创建bean的候选构造函数
    		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
    				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    			// 使用构造函数自动装配方式实例化bean
    			// 构造函数的参数会被作为依赖被解析和注入
    			return autowireConstructor(beanName, mbd, ctors, args);
    		}
    
    		// Preferred constructors for default construction?
    		ctors = mbd.getPreferredConstructors();
    		if (ctors != null) {
    			// 使用构造函数自动装配方式实例化bean
    			// 构造函数的参数会被作为依赖被解析和注入
    			return autowireConstructor(beanName, mbd, ctors, null);
    		}
    
    		// No special handling: simply use no-arg constructor.
    		// 使用缺省构造函数实例化bean
    		// 缺省构造函数也就是一般所说的无参构造函数
    		return instantiateBean(beanName, mbd);
    	}
    

    从上面的代码可见,如果bean创建需要使用带参数的构造函数,也就是类似例子BeanB(BeanA a)情况,则在目标bean实例创建的过程中,就会通过方法autowireConstructor使用相应的构造函数进行实例的创建,而在此过程中,首先就需要将构造函数的参数作为依赖被解析。具体我们来看autowireConstructor的实现 :

    
    	/**
    	 * "autowire constructor" (with constructor arguments by type) behavior.
    	 * Also applied if explicit constructor argument values are specified,
    	 * matching all remaining arguments with beans from the bean factory.
         * 
         * This corresponds to constructor injection: In this mode, a Spring
    	 * bean factory is able to host components that expect constructor-based
    	 * dependency resolution.
    	 * @param beanName the name of the bean
    	 * @param mbd the bean definition for the bean
    	 * @param ctors the chosen candidate constructors
    	 * @param explicitArgs argument values passed in programmatically via the getBean method,
    	 * or  null if none (-> use constructor argument values from bean definition)
    	 * @return a BeanWrapper for the new instance
    	 */
    	protected BeanWrapper autowireConstructor(
    		   String beanName, RootBeanDefinition mbd, 
                @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
    
    		return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
    	}
    

    从该方法可见,此过程是使用当前容器BeanFactory构造了一个ConstructorResolver,然后调用委托该ConstructorResolver对象的方法autowireConstructor完成最终的构造函数依赖解析和目标bean的创建。

    ConstructorResolver#autowireConstructor对目标bean的创建,又可以基本上分为两个步骤:

    1. 解析构造函数参数依赖的bean
    2. 调用相应的构造函数创建目标bean

    而上面的第一步如下所示 :

    	/**
    	 * Create an array of arguments to invoke a constructor or factory method,
    	 * given the resolved constructor argument values.
    	 */
    	private ArgumentsHolder createArgumentArray(
    			String beanName, RootBeanDefinition mbd, 
    			@Nullable ConstructorArgumentValues resolvedValues,
    			BeanWrapper bw, Class<?>[] paramTypes, 
    			@Nullable String[] paramNames, Executable executable,
    			boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
    
    		TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
    		TypeConverter converter = (customConverter != null ? customConverter : bw);
    
    		ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
    		Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
    		Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
    
    		for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
    			Class<?> paramType = paramTypes[paramIndex];
    			String paramName = (paramNames != null ? paramNames[paramIndex] : "");
    			// Try to find matching constructor argument value, either indexed or generic.
    			ConstructorArgumentValues.ValueHolder valueHolder = null;
    			if (resolvedValues != null) {
    				valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, 
    					paramName, usedValueHolders);
    				// If we couldn't find a direct match and are not supposed to autowire,
    				// let's try the next generic, untyped argument value as fallback:
    				// it could match after type conversion (for example, String -> int).
    				if (valueHolder == null && (!autowiring 
    					|| paramTypes.length == resolvedValues.getArgumentCount())) {
    					valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
    				}
    			}
    			if (valueHolder != null) {
    				// We found a potential match - let's give it a try.
    				// Do not consider the same value definition multiple times!
    				usedValueHolders.add(valueHolder);
    				Object originalValue = valueHolder.getValue();
    				Object convertedValue;
    				if (valueHolder.isConverted()) {
    					convertedValue = valueHolder.getConvertedValue();
    					args.preparedArguments[paramIndex] = convertedValue;
    				}
    				else {
    					MethodParameter methodParam = 
    						MethodParameter.forExecutable(executable, paramIndex);
    					try {
    						convertedValue = converter.convertIfNecessary(originalValue, 
    								paramType, methodParam);
    					}
    					catch (TypeMismatchException ex) {
    						throw new UnsatisfiedDependencyException(
    							mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
    							"Could not convert argument value of type [" +
    									ObjectUtils.nullSafeClassName(valueHolder.getValue()) +
    									"] to required type [" + paramType.getName() + "]: " + 
    									ex.getMessage());
    					}
    					Object sourceHolder = valueHolder.getSource();
    					if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
    						Object sourceValue = 
    							((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
    							
    						args.resolveNecessary = true;
    						args.preparedArguments[paramIndex] = sourceValue;
    					}
    				}
    				args.arguments[paramIndex] = convertedValue;
    				args.rawArguments[paramIndex] = originalValue;
    			}
    			else {
    				MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
    				// No explicit match found: we're either supposed to autowire or
    				// have to fail creating an argument array for the given constructor.
    				if (!autowiring) {
    					throw new UnsatisfiedDependencyException(
    						mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam),
    						"Ambiguous argument values for parameter of type [" + paramType.getName() +
    						"] - did you specify the correct bean references as arguments?");
    				}
    				try {
                     // 这里调用 resolveAutowiredArgument 方法解析一个构造函数参数对应的依赖bean
    					Object autowiredArgument = resolveAutowiredArgument(
    							methodParam, beanName, autowiredBeanNames, converter, fallback);
    					args.rawArguments[paramIndex] = autowiredArgument;
    					args.arguments[paramIndex] = autowiredArgument;
    					args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
    					args.resolveNecessary = true;
    				}
    				catch (BeansException ex) {
    					throw new UnsatisfiedDependencyException(
    							mbd.getResourceDescription(), beanName, 
    							new InjectionPoint(methodParam), ex);
    				}
    			}
    		}
    
    		for (String autowiredBeanName : autowiredBeanNames) {
    			this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
    			if (logger.isDebugEnabled()) {
    				logger.debug("Autowiring by type from bean name '" + beanName +
    				"' via " + (executable instanceof Constructor ? "constructor" : "factory method") +
    				" to bean named '" + autowiredBeanName + "'");
    			}
    		}
    
    		return args;
    	}
    

    而上面的方法又会使用如下方法解析每个构造函数参数的值 :

    	@Nullable
    	protected Object resolveAutowiredArgument(MethodParameter param, String beanName,
    			@Nullable Set<String> autowiredBeanNames, TypeConverter typeConverter, boolean fallback) {
    
    		Class<?> paramType = param.getParameterType();
    		if (InjectionPoint.class.isAssignableFrom(paramType)) {
    			InjectionPoint injectionPoint = currentInjectionPoint.get();
    			if (injectionPoint == null) {
    				throw new IllegalStateException("No current InjectionPoint available for " + param);
    			}
    			return injectionPoint;
    		}
    		try {
                // 最终通过 beanFactory.resolveDependency 获取当前方法参数所对应的依赖bean
    			return this.beanFactory.resolveDependency(
    										new DependencyDescriptor(param, true), 
    										beanName, 
    										autowiredBeanNames, 
    										typeConverter);
    		}
    		catch (NoUniqueBeanDefinitionException ex) {
    			throw ex;
    		}
    		catch (NoSuchBeanDefinitionException ex) {
    			if (fallback) {
    				// Single constructor or factory method -> let's return an empty array/collection
    				// for e.g. a vararg or a non-null List/Set/Map parameter.
    				if (paramType.isArray()) {
    					return Array.newInstance(paramType.getComponentType(), 0);
    				}
    				else if (CollectionFactory.isApproximableCollectionType(paramType)) {
    					return CollectionFactory.createCollection(paramType, 0);
    				}
    				else if (CollectionFactory.isApproximableMapType(paramType)) {
    					return CollectionFactory.createMap(paramType, 0);
    				}
    			}
    			throw ex;
    		}
    	}
    

    从上面的分析可以看出,构造函数参数所对应的依赖最终由beanFactory.resolveDependency最终解析得到。关于beanFactory.resolveDependency是如何工作的,你可以参考 : “Spring 依赖解决过程分析”。

    展开全文
  • 创建Bean构造函数方式

    千次阅读 2018-08-01 19:36:10
    通过构造函数来创建Bean的方式 下面是一个类: Foo类有两个构造函数 一个有参 一个无参 public class Foo{  private String name;    public Foo(){  }    public Foo(String name){  this.name = name;  } ...

    通过构造函数来创建Bean的方式
    下面是一个类:
    Foo类有两个构造函数
    一个有参
    一个无参
    public class Foo{
        private String name;
        
        public Foo(){

        }
       
        public Foo(String name){
           this.name = name;
        }
         
        public String getName(){
           return name;
        }
        
        public void setName(String name){
           this.name = name;
        
        }
    }

    下面是两个Bean定义:

    <bean id="foo1" class="com.wiley.beginningspring.ch2.Foo">
         <property name="name" value="fool"/>
    </bean>

    //很显然,创建这个bean时调用了无参数的构造方法
    //调用空参构造方法后就是一空壳子
    //属性的设置通过调用setter方法完成具体实现如下:
    //property元素通过name指定属性名称 通过value特性指定属性的值

    <bean id="foo2" class="com.wiley.beginningspring.ch2.Foo">
        <constructor-arg value="foo2">
    </bean>


    //创建这个bean显然是通过构造函数来实现的
    //而且调用的构造函数是有参数的那一个
    //且传递给参数的值是foo2
     

    展开全文
  • spring bean构造函数

    千次阅读 2008-09-27 22:02:00
    可以在配制文件中进行实例化,但有时更希望可以在...那么就要在配置文件中增加一个参数constrator-org, 例如://此方法中有一个构造函数, package spring02; public class SimpleBean { private String name ;
      
    

    可以在配制文件中进行实例化,但有时更希望可以在对象实例化时通过构造方法实例化。

    Bean中增加一个构造方法。那么就要在配置文件中增加一个参数constrator-org

     

     

     

    例如:

    //此方法中有一个构造函数,

     

    package spring02;

     

    public class SimpleBean {

        private String name ;

        private String password ;

       

        public SimpleBean(String name,String password)

        {

           this.setName(name) ;

           this.setPassword(password) ;

        }

       

        public String getName() {

           return name;

        }

        public void setName(String name) {

           this.name = name;

        }

        public String getPassword() {

           return password;

        }

        public void setPassword(String password) {

           this.password = password;

        }

    }

     

    ==========================================

     

    //上面用到了构造函数,这里就要用<constructor-arg index="0">

     

    <?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-2.0.xsd">

        <bean id="simple" class="spring02.SimpleBean">

            <constructor-arg index="0">

               <value>朱庆良</value>

           </constructor-arg>

               <constructor-arg index="1">

               <value>123456</value>

           </constructor-arg>

        </bean>

     

    </beans>

     

    ===============================================

     

     

    //测试

    package spring02;

     

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

     

    public class Test {

        public static void main(String[] args) {

           ApplicationContext context = null ;

           context = new ClassPathXmlApplicationContext("applicationContext.xml") ;

           SimpleBean simple = (SimpleBean)context.getBean("simple") ;

           System.out.println("姓名:"+simple.getName()) ;

           System.out.println("密码:"+simple.getPassword()) ;

        }

     

    }

    展开全文
  • 首先,spring的加载顺序是先构造函数,之后注入类似@Autowried,@Value。 目前有个场景,需要在构造函数内注入配置文件中属性值,示例如下: public abstract class SomeBase { private String variable; public...

    首先,spring的加载顺序是先构造函数,之后注入类似@Autowried,@Value。

    目前有个场景,需要在构造函数内注入配置文件中属性值,示例如下:

    public abstract class SomeBase {
    
        private String variable;
    
        public SomeBase(String v){
            this.variable = v;
        }
    }
    
    @Service
    public class Test extend SomeBase{
    
        @Value("${test.properties:aa}")
        private String variable;
    
        public Test(){
            super(variable);
        }
    }
    

    注意这样是行不通的,IDE给出的编译错误信息如下:

    Cannot reference 'xx' before supertype constructor has been called
    

    主要原因是spring在进行初始化bean时,由于先进行构造函数,而后进行注入,所以导致spring不认可这种做法。

    原因说清楚了,关键是,怎么解决呢?通过各位猿哥哥的博客翻阅,最终通过如下方式注入:

    @Service
    public class Test extend SomeBase{
    
        public Test(@Value("${test.properties:aa}") String variable){
            super(variable);
        }
    }
        
    

    到此,问题得以解决。

    总结:spring对bean的注入顺序是无法改变的,但是它提供了别的机制容许我们实现短暂的顺序调整,这种编码思路和风格值得我们学习。

    展开全文
  • 深入Bean属性和构造函数参数 bean的属性和构造函数参数可以被定义为其他bean的引用(合作者),或者内联定义的值。为达到这个目的,XmlBeanFactory在property和constructor-arg元素中支持很多子元素类型。 value元素...
  • spring中bean构造函数,Autowired(Value)注入与@PostConstruct调用顺序 最近在项目开发中遇到这样一个需求,由于元数据在短时间内被客户端多次读取,因此希望直接将数据存储到内存,以减少网络开销,借助guava ...
  • 1. 这个class的构造函数被执行; 2.Setter被执行; 3.如果这个class实现了InitializingBean(即implements InitializingBean)则,接下来执行public void afterPropertiesSet() throws Exception() 中的内容。
  • 如何使用指定的构造函数来构造bean
  • SpringBoot构建带有含参构造函数Bean
  • @Autowired和构造函数bean的注入问题

    千次阅读 2019-04-01 14:11:07
    近期看同事用idea开发的代码,发现在使用@Autowired的时候,大多使用构造函数进行注入。 以前自己在写代码的时候都是直接在变量上进行注入,也没注意过,查了些资料,发现如果直接在变量上进行注入,那么可能会造成...
  • spring bean 的配置-不同构造函数

    千次阅读 2011-12-15 13:09:15
    使用构造子注入时,则使用constructor-arg子标签,来指定构造函数的参数。 This is a configurable message  当构造函数有多个参数时,可以使用constructor-arg标签的index属性,index属性的值从0开始。 ...
  • 在Spring的Bean注入中,即使你私有化构造函数,默认他还是会去调用你的私有构造函数去实例化。 如果我们想保证实例的单一性,就要在定义<bean>时加上factory-method=””的属性,并且在私有构造函数中添加...
  • Spring Bean xml显式装配之构造函数

    千次阅读 2017-05-30 22:23:57
    对于喜欢用xml配置文件来说,xml装配bean 例子还是老师注入学生bean 1.老师和学生接口 package com.jack.bean.chatpter2.autowiredBeanJava; public interface Student { void learn(); } package ...
  • FAQ(8):spring:遗漏编写bean的无参构造函数
  • 1.xml文件 <bean id="aaa" class="com.dingwang.Test.Aaa" init-method="init"> <constructor-arg name="name" value="ddd"></constructor-arg> ...执行顺序:构造函数>afterPropertiesSet>init-method
  • Spring4.0 构造函数配置bean

    千次阅读 2016-06-17 17:09:50
    Spring IOC 下面代码就是Spring的IOC ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); ...Spring的两种getBean() ...HelloWorld helloworld = (HelloWorld) ctx....
  • createBeanInstance() 用于实例化 bean,它会根据不同情况选择不同的实例化策略来完成 bean 的初始化,主要包括: Supplier 回调:obtainFromSupplier() 工厂方法初始化:... 默认构造函数注入:instantiat...
  • spring 构造函数注入 在运行时,除非在启用了调试选项的情况下编译类,否则Java类不会保留构造函数或方法参数的名称。 这对于Spring构造函数注入有一些有趣的含义。 考虑以下简单的类 package dbg; public...
  • 上一节讲到了无参构造函数的实例化bean, 这节介绍只有一个有参的构造函数bean实例化,以 @Component("lmqsthird") public class LmqDao23456 { public LmqDao23456(LmqDao2 lmq) { } public void ...
  • 1. 通过类的带参数构造函数的方法 2. 通过类的set方法 在 JavaBean 里,一般参数在4个以上的,极不推荐使用带参数构造函数赋值: 1. 对于一个实体类,对于多个参数,降低可读性 2. 需要记住构造参数的顺序 3. 一...
  • JAVAEE中,javaBean是一个很重要...1. 通过类的带参数构造函数的方法 2. 通过类的set方法 在javaBean里,一般参数在4个以上的,极不推荐使用带参数构造函数赋值: 1. 对于一个实体类,对于多个参数,降低可读性 2...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 86,343
精华内容 34,537
关键字:

bean构造函数