te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>java - spring multiple constructor injection without @Autowiring - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - spring multiple constructor injection without @Autowiring - Stack Overflow

programmeradmin4浏览0评论

I’m trying to use constructor injection. I understand that when Spring finds multiple constructors, it will try to choose the one with the largest number of arguments where the types match Spring-managed beans. However, in this example, it fails. Normally, it should call the second constructor.

package autowiring;

import .springframework.stereotype.Component;

import .springframework.context.annotation.Configuration;
import .springframework.context.annotation.ComponentScan;
import .springframework.context.annotation.AnnotationConfigApplicationContext;

@Configuration
@ComponentScan
class config{

}

@Component
public class comp1{
    Foo ab;
    Boo bo;
    public  comp1(Foo ab,String a,X d){
        System.out.println("constructor 1 called");

        this.ab=ab;
    }
    public comp1(Foo ab,Boo bo){
       System.out.println("constructor 2 called");
        this.ab=ab;
        this.bo=bo;
    }
    public static void main(){
        var ctx=new AnnotationConfigApplicationContext(config.class);
    }
}

@Component
class Foo{
    String name="Foo";
}

@Component
class Boo{
    String name="Bar";
}

class X{

}

The output:

amdi@debian:~/Documents/learn/java2/test$ java -jar target/my*.jar
Feb 18, 2025 6:39:04 AM .springframework.context.support.AbstractApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: .springframework.beans.factory.BeanCreationException: Error creating bean with name 'comp1' defined in URL [jar:file:/home/lmhamdi/Documents/learn/java2/test/target/my-app-1.0.0.jar!/autowiring/comp1.class]: Instantiation of bean failed; nested exception is .springframework.beans.BeanInstantiationException: Failed to instantiate [autowiringp1]: No default constructor found; nested exception is java.lang.NoSuchMethodException: autowiringp1.<init>()
Exception in thread "main" .springframework.beans.factory.BeanCreationException: Error creating bean with name 'comp1' defined in URL [jar:file:/home/lmhamdi/Documents/learn/java2/test/target/my-app-1.0.0.jar!/autowiring/comp1.class]: Instantiation of bean failed; nested exception is .springframework.beans.BeanInstantiationException: Failed to instantiate [autowiringp1]: No default constructor found; nested exception is java.lang.NoSuchMethodException: autowiringp1.<init>()
        at .springframe

I’m trying to use constructor injection. I understand that when Spring finds multiple constructors, it will try to choose the one with the largest number of arguments where the types match Spring-managed beans. However, in this example, it fails. Normally, it should call the second constructor.

package autowiring;

import .springframework.stereotype.Component;

import .springframework.context.annotation.Configuration;
import .springframework.context.annotation.ComponentScan;
import .springframework.context.annotation.AnnotationConfigApplicationContext;

@Configuration
@ComponentScan
class config{

}

@Component
public class comp1{
    Foo ab;
    Boo bo;
    public  comp1(Foo ab,String a,X d){
        System.out.println("constructor 1 called");

        this.ab=ab;
    }
    public comp1(Foo ab,Boo bo){
       System.out.println("constructor 2 called");
        this.ab=ab;
        this.bo=bo;
    }
    public static void main(){
        var ctx=new AnnotationConfigApplicationContext(config.class);
    }
}

@Component
class Foo{
    String name="Foo";
}

@Component
class Boo{
    String name="Bar";
}

class X{

}

The output:

amdi@debian:~/Documents/learn/java2/test$ java -jar target/my*.jar
Feb 18, 2025 6:39:04 AM .springframework.context.support.AbstractApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: .springframework.beans.factory.BeanCreationException: Error creating bean with name 'comp1' defined in URL [jar:file:/home/lmhamdi/Documents/learn/java2/test/target/my-app-1.0.0.jar!/autowiring/comp1.class]: Instantiation of bean failed; nested exception is .springframework.beans.BeanInstantiationException: Failed to instantiate [autowiringp1]: No default constructor found; nested exception is java.lang.NoSuchMethodException: autowiringp1.<init>()
Exception in thread "main" .springframework.beans.factory.BeanCreationException: Error creating bean with name 'comp1' defined in URL [jar:file:/home/lmhamdi/Documents/learn/java2/test/target/my-app-1.0.0.jar!/autowiring/comp1.class]: Instantiation of bean failed; nested exception is .springframework.beans.BeanInstantiationException: Failed to instantiate [autowiringp1]: No default constructor found; nested exception is java.lang.NoSuchMethodException: autowiringp1.<init>()
        at .springframe
Share Improve this question edited 2 days ago dani-vta 7,0557 gold badges49 silver badges65 bronze badges asked 2 days ago samhsamh 313 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 2

Only one constructor of any given bean class may declare @Autowired with the required attribute set to true, indicating the constructor to autowire when used as a Spring bean. As a consequence, if the required attribute is left at its default value true, only a single constructor may be annotated with @Autowired. If multiple constructors declare the annotation, they will all have to declare required=false in order to be considered as candidates for autowiring (analogous to autowire=constructor in XML). The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a primary/default constructor (if present) will be used. Similarly, if a class declares multiple constructors but none of them is annotated with @Autowired, then a primary/default constructor (if present) will be used. If a class only declares a single constructor to begin with, it will always be used, even if not annotated. Note that an annotated constructor does not have to be public.

This is from the referenece guide and, is pretty clear on the resolution strategy. It explicitly mentions what happens if there are multiple annotations and none of them are annotation with @Autowired. That is the part that I highlighted.

What you state is true but only for constructors that are annotated with @Autowired. Hence if you want what you already think is happening you need to autowire your constructors with @Autowired(required=false) and then Spring will detect the best matching one.

@Component
public class comp1{
    Foo ab;
    Boo bo;

    @Autowired(required=false)    
    public  comp1(Foo ab,String a,X d){
        System.out.println("constructor 1 called");

        this.ab=ab;
    }

    @Autowired(required=false)
    public comp1(Foo ab,Boo bo){
       System.out.println("constructor 2 called");
        this.ab=ab;
        this.bo=bo;
    }
    public static void main(){
        var ctx=new AnnotationConfigApplicationContext(config.class);
    }
}

According to Using @Autowired from the framwork reference, Spring automatically matches dependencies by type with no @Autowired configuration, only if a bean exhibits a single arg-constructor.

As of Spring Framework 4.3, an @Autowired annotation on such a constructor is no longer necessary if the target bean defines only one constructor to begin with.

In your case, comp1 provides multiple constructors. Therefore, you need to tell Spring how you want to wire the bean's dependencies. Without any form of wiring configuration (@Autowired, @Resource, or @Inject), Spring tries to instantiate the bean via a no-arg constructor, but since there isn't one, a BeanCreationException is thrown.

To fix your issue, you could simply annotate comp1's second constructor with @Autowired.

@Component
class Foo{
    String name="Foo";
}

@Component
class Boo{
    String name="Bar";
}

@Component
public class comp1{
    Foo ab;
    Boo bo;

    public comp1(Foo ab, String a, X d){
        System.out.println("constructor 1 called");
        this.ab=ab;
    }

    @Autowired
    public comp1(Foo ab, Boo bo){
        System.out.println("constructor 2 called");
        this.ab=ab;
        this.bo=bo;
    }

    public static void main(){
        var ctx=new AnnotationConfigApplicationContext(config.class);
    }
}
发布评论

评论列表(0)

  1. 暂无评论