精华内容
下载资源
问答
  • 2019-10-14 09:40:43

    目录

    1.setter 方法注入

    2.构造函数注入

    3.注解注入


    Spring 中的IOC 就是控制bean的容器,各个bean 之间会存在相互的引用,那在各个bean之间如何引用就显得尤为重要。

    Spring 中常见的注入方法主要有:setter方法注入,构造函数注入,注解注入。

    1.setter 方法注入

    这种注入要是依赖于配置文件中注入

    配置文件如下:

    <bean id="userService" class="com.spring.UserService">
    	<property name="userDao" ref="userDao"></property>
    </bean>
    
    <bean id="userDao" class="com.spring.dao.UserDao"></bean>
    

    Spring会将property中name值的每个单词首字母转换成大写,然后再在前面拼接上"set"构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入。

    对应的JAVA代码:

    public class UserService{
    
    	private UserDao userDao;
    	
    	public void setUserDao(UserDao userDao) {
    		this.userDao = userDao;
    	}
    
    }
    

    有一点需要注意:如果通过set方法注入属性,那么spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则spring没有办法实例化对象,导致报错。

    2.构造函数注入

    在配置文件中,通过constructor-args 标签注入到对应的bean 中。

    <bean id="userService" class="com.spring.UserService">
    	<constructor-arg ref="userDao"></constructor-arg>
    </bean>
    <bean id="userDao" class="com.spring.dao.UserDaoJdbc"></bean>

    对应的JAVA类:

    public class UserService{
    
    	private UserDao userDao;
    	
    	public UserService(UserDao userDao) {
    		this.userDao = userDao;
    	}
    
    }
    

    关于构造函数的注入,也会涉及到多个构造函数如何匹配的问题,这里可以通过配置文件中的index 以及type进行匹配。示例中,本来就只有一个参数的构造函数,比较简单。

    3.注解注入

    主要有4种注解的类可以注册bean,每种注解可以任意使用,只是语义上有所差异:

    @Component 可以用于注册所有bean

    @Controller 可以用于注册控制层的bean

    @Service 可以用于注册服务层的bean

    @Repository 可以用于注册dao层的bean

    描述依赖关系的的主要有2种:

    @Resource(java 注解)默认以byName的方式去匹配与属性名相同的bean 的id,如果没有找到就以byType的方式查找,如果byType找到多个,通过@Qualifier 注解(Spring注解)指定某个具体名称的bean。

    @Autowired (Spring 注解) 默认以byType的方式去匹配类型相同的bean,如果只匹配到一个,那么就直接注入该bean,此时不论要注入的bean的name 是什么。如果匹配到多个,就会调用DefaultListableBeanFactory 的determineAutowireCandidate 方法来决定具体注入哪个bean。

    determineAutowireCandidate 方法的逻辑是:

    1. 先找 Bean 上有@Primary 注解的,有则直接返回 bean 的 name。
    2. 再找 Bean 上有 @Order,@PriorityOrder 注解的,有则返回 bean 的 name。
    3. 最后再以名称匹配(ByName)的方式去查找相匹配的 bean。

    可以简单的理解为先以 ByType 的方式去匹配,如果匹配到了多个再以 ByName 的方式去匹配,找到了对应的 bean 就去注入,没找到就抛出异常。


    在配置文件中,bean的配置属性autowire有以下几种类型:

    先看示例:

    <bean id="auto" class="example.autoBean" autowire="byType"/>
    1. no:不采用autowire 机制,这种情况,当我们需要使用依赖注入时,只能使用</ref>标签
    2. byName:通过属性的名称自动装配(注入)。spring 会在容器中查找名称与bean属性名称一致的bean,并自动注入到bean的属性中。
    3. byType:通过类型自动装配(注入)。spring 会在容器中查找class与bean 属性类一致的bean,并自动注入到bean的属性中。
    4. constructor:类似于byType,但是通过构造函数的参数类型来匹配。
    5. default:采用父级标签(即beans的 default-autowire属性)的配置

     

    更多相关内容
  • 主要介绍了详解Spring中bean的几种注入方式,主要介绍了4种注入,主要有属性注入、构造函数注入、工厂方法注入,非常具有实用价值,需要的朋友可以参考下
  • 本篇文章主要介绍了Spring Bean三种注入方式详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • NULL 博文链接:https://shmilyaw-hotmail-com.iteye.com/blog/2169569
  • NULL 博文链接:https://gary0416.iteye.com/blog/889228
  • 本篇文章主要介绍了Spring 依赖注入几种方式详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • NULL 博文链接:https://gary0416.iteye.com/blog/890689
  • 主要给大家介绍了关于spring boot中几种注入方法的一些个人看法,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • 主要介绍了Spring中属性注入几种方式以及复杂属性的注入详解,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Spring依赖注入方式

    2019-04-19 01:40:32
    NULL 博文链接:https://huangminwen.iteye.com/blog/1041743
  • 主要介绍了Spring为IOC容器注入Bean的五种方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Spring依赖注入(DI)的三种方式,分别为: 1. 接口注入 2. Setter方法注入 3. 构造方法注入 下面介绍一下这三种依赖注入Spring中是怎么样实现的。 首先我们需要以下个类: 接口 Logic.java 接口实现类 ...
  • spring注入对象的几种方式

    千次阅读 2021-02-19 18:53:17
    spring通过IOC容器帮我们管理了对象,但是管理的这些对象,当我们需要其中一个或者是多个的时候应该怎么样获取呢,这就和对象注入有关系了,通过注入,我们可以从spring容器中反向被动的获取对象,然后就可以使用...

    写在前面

    spring通过IOC容器帮我们管理了对象,但是管理的这些对象,当我们需要其中一个或者是多个的时候应该怎么样获取呢,这就和对象注入有关系了,通过注入,我们可以从spring容器中反向被动的获取对象,然后就可以使用这些对象的能力来完成我们的任务了。

    1:setter方法注入

    其实就是属性值入。

    1.1:定义注入的类

    public class MyDao {
    }
    

    1.2:定义被注入的类

    public class MyAction {
        private MyDao myDao;
    
        public MyDao getMyDao() {
            return myDao;
        }
    
        public void setMyDao(MyDao myDao) {
            this.myDao = myDao;
        }
    }
    

    1.3:定义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="myDao" class="yudaosourcecode.spring.MyDao"/>
        <bean id="myAction" class="yudaosourcecode.spring.MyAction">
            <property name="myDao" ref="myDao"/>
        </bean>
    </beans>
    

    1.4:测试

    @Test
    public void testDiBySetter() {
        ApplicationContext ac =
                new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        MyAction myAction = ac.getBean("myAction", MyAction.class);
        System.out.println("myAction.getMyDao(): ");
        System.out.println(myAction.getMyDao());
    }
    

    运行:

    myAction.getMyDao(): 
    yudaosourcecode.spring.MyDao@75881071
    

    2:构造器注入

    2.1:定义注入的类

    public class DiPerson {
    }
    public class DiUser {
    }
    

    2.2:定义被注入的类

    public class ConstructorDi {
        public DiPerson diPerson;
        public DiUser diUser;
    
        public ConstructorDi(DiPerson diPerson, DiUser diUser) {
            this.diPerson = diPerson;
            this.diUser = diUser;
        }
    }
    

    注意其中的private DiPerson diPersonprivate DiUser diUser我们没有定义读写方法。

    2.3:定义xml

    <beanid="myPerson" class="yudaosourcecode.spring.DiPerson"/>
    <bean id="myUser" class="yudaosourcecode.spring.DiUser"/>
    <bean id="constructorDi" class="yudaosourcecode.spring.ConstructorDi">
        <!--
        public ConstructorDi(DiPerson diPerson, DiUser diUser) {
            this.diPerson = diPerson;
            this.diUser = diUser;
        }
        -->
        <constructor-arg index="0" ref="myPerson"/>
        <constructor-arg index="1" ref="myUser"/>
    </bean>
    

    2.4:测试

    @Test
    public void diByConstructorTest() {
        ClassPathXmlApplicationContext ac
                = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        ConstructorDi constructorDi = ac.getBean("constructorDi", ConstructorDi.class);
        System.out.println("constructorDi.diPerson is: ");
        System.out.println(constructorDi.diPerson);
        System.out.println("constructorDi.diUser is: ");
        System.out.println(constructorDi.diUser);
    }
    

    输出:

    constructorDi.diPerson is: 
    yudaosourcecode.spring.DiPerson@7403c468
    constructorDi.diUser is: 
    yudaosourcecode.spring.DiUser@43738a82
    
    Process finished with exit code 0
    

    3:静态工厂方法注入

    这种方式其实是调用调用某个类的静态方法来获取需要需要的对象来进行注入。

    3.1:定义注入的类

    public class DiPerson {
    }
    

    3.2:定义静态工厂类

    该静态工厂类提供静态方法返回DiPerson对象:

    public class StaticFactoryCls {
    
        public static final DiPerson generatePersonDi() {
            return new DiPerson();
        }
    }
    

    3.3:定义被注入的类

    public class StaticFactoryMethodDi {
        private DiPerson diPerson;
    
        public DiPerson getDiPerson() {
            return diPerson;
        }
    
        public void setDiPerson(DiPerson diPerson) {
            this.diPerson = diPerson;
        }
    }
    

    3.4:定义xml

    <!-- 通过工厂方法定义bean -->
    <bean id="staticFactoryDiPerson" class="yudaosourcecode.spring.StaticFactoryCls" factory-method="generatePersonDi"/>
    <bean id="staticFactoryMethodDi" class="yudaosourcecode.spring.StaticFactoryMethodDi">
        <property name="diPerson" ref="staticFactoryDiPerson"/>
    </bean>
    

    3.5:测试

    staticFactoryMethodDi.getDiPerson() is: 
    yudaosourcecode.spring.DiPerson@67b467e9
    
    Process finished with exit code 0
    

    4:实例工厂方法注入

    这种方式和静态工厂方法注入的唯一区别就是生成对象的方法是实例方法,而不是静态方法。

    4.1:定义注入的类

    public class DiPerson {
    }
    

    4.2:定义实例工厂类

    public class InstanceFactoryCls {
        public DiPerson generatePersonDi() {
            return new DiPerson();
        }
    }
    

    注意这里的方法是实例方法,而不是静态方法了。

    4.3:定义被注入的类

    public class InstanceFactoryMethodDi {
        private DiPerson diPerson;
        public DiPerson getDiPerson() {
            return diPerson;
        }
    
        public void setDiPerson(DiPerson diPerson) {
            this.diPerson = diPerson;
        }
    
    }
    

    4.4:定义xml

    <!-- 定义实例工厂bean -->
    <bean id="instanceFactoryCls" class="yudaosourcecode.spring.InstanceFactoryCls"/>
    <!-- 通过实例工厂bean获取需要DI的bean -->
    <bean id="instanceFactoryDiPerson"
          factory-bean="instanceFactoryCls"
          factory-method="generatePersonDi"/>
    <bean id="instanceFactoryMethodDi" class="yudaosourcecode.spring.InstanceFactoryMethodDi">
        <property name="diPerson" ref="instanceFactoryDiPerson"/>
    </bean>
    

    4.5:测试

    @Test
    public void diByInstanceFactoryTest() {
        ClassPathXmlApplicationContext ac
                = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
        InstanceFactoryMethodDi instanceFactoryMethodDi = ac.getBean("instanceFactoryMethodDi", InstanceFactoryMethodDi.class);
        System.out.println("instanceFactoryMethodDi.getDiPerson() is: ");
        System.out.println(instanceFactoryMethodDi.getDiPerson());
    }
    

    运行:

    instanceFactoryMethodDi.getDiPerson() is: 
    yudaosourcecode.spring.DiPerson@5c072e3f
    
    Process finished with exit code 0
    
    展开全文
  • Spring】依赖注入几种方式

    千次阅读 2022-01-18 18:24:51
    Spring依赖注入几种方式详细实现及其优缺点分析

            在上篇文章中我着重介绍了Spring的控制反转和依赖注入的概念,那么依赖注入有那几种方式呢?他们的优缺点分别是什么,我将在本章中详细讲解。

            Spring的依赖注入根据对象类型注入可以分为属性注入和对象注入,根据注入的方式可以分成xml配置文件注入和注解注入,其中xml有三种注入方式:

    1. 构造方法注入;
    2. setter方法注入;
    3. p名称空间注入。

    注意:P名称空间为特殊的setter方法注入,因此也有人说xml有两种注入方式,本文为了详细介绍,所以分开讲解。

    注解注入的方式分成三种:

    1. 构造方法注入;
    2. setter方法注入;
    3. 自动注入。

    一、对象注入

    1.1、xml文件注入

    1.1.1、构造方法注入

    public class A {
    
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    
        public A(B b, String name) {
            this.b = b;
            this.name = name;
        }
    }
    public class B {
    
        private String name;
    
        private Double age;
    
        public B(String name, Double age) {
            this.name = name;
            this.age = age;
        }
    
        public void b(){
            System.out.println("B中b方法执行了,name=" + name + ",age=" + age);
        }
    }
        <!--创建B的Bean对象-->
        <!--
            constructor-arg:构造函数赋值,
            注意:需要提供一个有参的构造函数
            有以下取值:
                name:构造函数所需要的参数名称
                value:参数名称对应的值
                ref:参数为其他bean
                type:指定参数在构造函数中的数据类型
                index:指定参数在构造函数中的索引位置 -->
        <bean id="b" class="com.sxx.service.entity.B">
            <constructor-arg name="name" value="张三"/>
            <constructor-arg name="age" value="12.58"/>
        </bean>
    
        <bean name="a" class="com.sxx.service.entity.A">
            <constructor-arg name="b" ref="b"/>
            <constructor-arg name="name" value="王五"/>
        </bean>
    public class IocTest {
        public static void main(String[] args) {
            ApplicationContext applicationContext =
                    new ClassPathXmlApplicationContext("bean.xml");
            A a = (A) applicationContext.getBean("a");
            a.a();
        }
    }

    B中b方法执行了,name=张三,age=12.58
    A中a方法执行了,name=王五

    1.1.2、set方法注入

    public class A {
    
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    }
    public class B {
    
        private String name;
    
        private String age;
    
        public void b(){
            System.out.println("B中b方法执行了,name=" + name + ",age=" + age);
        }
    }
        <!--创建B的Bean对象-->
         <!--
            property:赋值属性,有以下取值:
                name:类中的属性值,实际找的是set方法对应的属性,比如setName -> name才能在此赋值,没有set方法会报错;
                value:给属性赋值,基本数据和String类型的用此种方法;
                ref:属性赋值是其他bean类型的
        -->
        <bean id="b" class="com.sxx.service.entity.B">
            <property name="name" value="张三"/>
            <property name="age" value="12"/>
        </bean>
         <bean name="a" class="com.sxx.service.entity.A">
            <property name="name" value="李四"/>
            <!--ref指向的是上面id="b"-->
            <property name="b" ref="b"/>
        </bean>
    public class IocTest {
        public static void main(String[] args) {
           ApplicationContext applicationContext =
                    new ClassPathXmlApplicationContext("bean.xml");
            A a = (A) applicationContext.getBean("a");
            a.a();
            B b = (B) applicationContext.getBean("b");
            b.b();
        }
    }

     结果如下:

    B中b方法执行了,name=张三,age=12.58
    A中a方法执行了,name=李四
    B中b方法执行了,name=张三,age=12.58

    1.1.3、P名称空间注入

    public class A {
    
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    }
    public class B {
    
        private String name;
    
        private Double age;
    
        public void b(){
            System.out.println("B中b方法执行了,name=" + name + ",age=" + age);
        }
    }
    <?xml version="1.0" encoding="utf-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
        <bean id="a" class="com.sxx.service.entity.A"
                p:name="李四" p:b-ref="b">
        </bean>
        <bean id="b" class="com.sxx.service.entity.B">
            <property name="name" value="张三"/>
            <property name="age" value="12.58"/>
        </bean>
    
    </beans>
    public class IocTest {
        public static void main(String[] args) {
            ApplicationContext applicationContext =
                    new ClassPathXmlApplicationContext("bean.xml");
            A a = (A) applicationContext.getBean("a");
            a.a();
        }
    }

    B中b方法执行了,name=张三,age=12.58
    A中a方法执行了,name=李四

    1.2、注解注入

    1.2.1、构造方法注入

    public class A {
    
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    
        public A(B b, String name) {
            this.b = b;
            this.name = name;
        }
    }
    public class B {
    
        private String name;
    
        private Double age;
    
        public void b(){
            System.out.println("B中b方法执行了,name=" + name + ",age=" + age);
        }
    
        public B(String name, Double age) {
            this.name = name;
            this.age = age;
        }
    }
    @Configuration
    public class BeanConfig {
        @Bean("b")//指定name=b,而非默认B
        public B B(){
           return new B("张三", 12.4D);
        }
        @Bean
        public A a(){
           return new A(B(), "李四");
        }
    }
    <?xml version="1.0" encoding="utf-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
    	   http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
        <!--添加spring扫描,范围是com.sxx下所有包及其子包-->
        <context:component-scan base-package="com.sxx"/>
    </beans>
    public class IocTest {
        public static void main(String[] args) {
            ApplicationContext applicationContext =
                    new ClassPathXmlApplicationContext("bean.xml");
            A a = (A) applicationContext.getBean("a");
            a.a();
        }
    }

    B中b方法执行了,name=张三,age=12.4
    A中a方法执行了,name=李四

    1.2.2、setter方法注入

    public class A {
    
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    }
    public class B {
    
        private String name;
    
        private Double age;
    
        public void b(){
            System.out.println("B中b方法执行了,name=" + name + ",age=" + age);
        }
    }
    <!--添加spring扫描,范围是com.sxx下所有包及其子包-->
    <context:component-scan base-package="com.sxx"/>
    @Configuration
    public class BeanConfig 
        @Bean
        //如果没有指定A在Ioc容器中的key,默认为方法名
        public B b(){
            B b = new B();
            b.setName("张三");
            b.setAge(20D);
            return b;
        }
        @Bean
        //如果没有指定A在Ioc容器中的key,默认为方法名
        public A a(){
            A a = new A();
            //引入的是上面的b()方法
            a.setB(b());
            a.setName("李四");
            return a;
        }
    }
    public class IocTest {
        public static void main(String[] args) {
            ApplicationContext applicationContext =
                    new ClassPathXmlApplicationContext("bean.xml");
            A a = (A) applicationContext.getBean("a");
            a.a();
        }
    }

    B中b方法执行了,name=张三,age=20.0
    A中a方法执行了,name=李四

    1.2.3、自动注入

            自动注入最具代表性的就是@Resource和@Autowired两个注解,在容器中只存在单一对象的时候,两个注解功能都相同,可以相互的替换,不影响使用。

            但是如果存在多个对象的时候,@Autowired只根据type进行注入,不会去匹配name。如果涉及到type无法辨别注入对象时,那需要依赖@Qualifier或@Primary注解一起来修饰。

            @Resource 是JDK1.6支持的注解, 默认按照name进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名,按照名称查找。如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

    1.3、注解注入的另外一种形式

            上面我们列举的注解注入的方法是通过在配置文件BeanConfig实现依赖注入的方式,还有另外一种方式可以直接在class文件中直接用@Resource或@Autowired直接引入。

    1.3.1、构造方法注入

    @Component
    public class A {
    
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    
        @Autowired
        public A(B b) {
            this.b = b;
        }
    }
    @Component
    public class B {
    
        private String name;
    
        private Double age;
    
        public void b(){
            System.out.println("B中b方法执行了,name=" + name + ",age=" + age);
        }
    }
     <!--添加spring扫描,范围是com.sxx下所有包及其子包-->
     <context:component-scan base-package="com.sxx"/>
    public class IocTest {
        public static void main(String[] args) {
            ApplicationContext applicationContext =
                    new ClassPathXmlApplicationContext("bean.xml");
            A a = (A) applicationContext.getBean("a");
            a.a();
        }
    }

    B中b方法执行了,name=null,age=null
    A中a方法执行了,name=null

    1.3.2、setter方法注入

    @Component
    public class A {
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    
        @Autowired
        public void setB(B b) {
            this.b = b;
        }
    }

    其他方法及结果参照1.3.1 

    1.3.3、直接注入

    @Component
    public class A {
        @Autowired
        private B b;
    
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    }

    其他方法及结果参照1.3.1

    二、参数注入

     参数注入主要是通过@Value注入

    @Component
    public class A {
        @Autowired
        private B b;
    
        @Value("李四")
        private String name;
    
        public void a(){
            b.b();
            System.out.println("A中a方法执行了,name=" + name);
        }
    }
    @Component
    public class B {
    
        @Value("张三")
        private String name;
    
        @Value("20.4")
        private Double age;
    
        public void b(){
            System.out.println("B中b方法执行了,name=" + name + ",age=" + age);
        }
    }

    其他配置可以参照其他依赖注入的方式

    结果为:

    B中b方法执行了,name=张三,age=20.4
    A中a方法执行了,name=李四

    注意:@Value不仅可以自己配置属性还可以从配置文件或者配置中心中获取对应的属性 

    三、几种依赖注入的优缺点对比 

    3.1、构造器注入

            优点:基于构造器注入,会固定依赖注入的顺序,不允许我们创建的bean对象之间存在循环依赖关系,这样Spring能解决循环依赖的问题。

            缺点:使用构造器注入的缺点是,当我们构造器需要注入的对象比较多时,会显得我们的构造器,冗余,不美观,可读性差,也不易维护。

    3.2、基于setter方法注入

            优点:基于setter注入,只有对象是需要被注入的时候,才会注入依赖,而不是在初始化的时候就注入。

            缺点:当我们选择setter方法来注入的时候,我们不能将对象设为final的;

    3.3、基于自动注入

            优点:在成员变量上写上注解来注入,这种方式,精短,可读性高,不需要多余的代码,也方便维护。

            缺点:

                    1.这样不符合JavaBean的规范,而且很有可能引起空指针;

                    2.同时也不能将对象标为final的;

                    3.类与DI容器高度耦合,我们不能在外部使用它;

                    4.类不通过反射不能被实例化(例如单元测试中),你需要用DI容器去实例化它,这更像集成测试;

    展开全文
  • 主要介绍了Springbean的几种注入方式都了解吗,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • Spring 的三种注入方式

    千次阅读 2022-01-20 10:59:48
    spring 注入方式

    1. 实例的注入方式

    首先来看看 Spring 中的实例该如何注入,总结起来,无非三种:

    • 属性注入

    • set 方法注入

    • 构造方法注入

    我们分别来看下。

    1.1 属性注入

    属性注入是大家最为常见也是使用最多的一种注入方式了,代码如下:

    @Service
    public class BService {
        @Autowired
        AService aService;
        //...
    }
    

    这里是使用 @Autowired 注解注入。另外也有 @Resource 以及 @Inject 等注解,都可以实现注入。

    不过不知道小伙伴们有没有留意过,在 IDEA 里边,使用属性注入,会有一个警告⚠️:

    不推荐属性注入!

    原因我们后面讨论。

    1.2 set 方法注入

    set 方法注入太过于臃肿,实际上很少使用:

    @Service
    public class BService {
        AService aService;
    
        @Autowired
        public void setaService(AService aService) {
            this.aService = aService;
        }
    }
    

    这代码看一眼都觉得难受,坚决不用。

    1.3 构造方法注入

    构造方法注入方式如下:

    @Service
    public class AService {
        BService bService;
        @Autowired
        public AService(BService bService) {
            this.bService = bService;
        }
    }
    

    如果类只有一个构造方法,那么 @Autowired 注解可以省略;如果类中有多个构造方法,那么需要添加上 @Autowired 来明确指定到底使用哪个构造方法。

    2. 实例注入方式大 PK

    上面给大家列出来了三种注入方式,那么三种注入方式各自有何区别呢?

    结合 Spring 官方文档,我们来分析下。

    松哥翻出了 12 年前的 Spring3.0 的文档(https://docs.spring.io/spring-framework/docs/3.0.x/reference/beans.html),里边有如下一段话:

    我来简单翻译下(意译):

    使用构造方法注入还是使用 set 方法注入?由于构造方法注入和 set 方法注入可以混合使用,因此,如果需要强制注入,我们可以使用构造方法注入的方式;如果是可选注入,则我们可以使用 set 方法注入的方式。当然,我们在 setter 上使用 @Required 注解可以让 set 方法注入也变为强制性注入。Spring 团队通常提倡 setter 注入,因为当属性特别多的时候,构造方法看起来会特别臃肿,特别是当属性是可选的时(属性可选意味着没必要通过构造方法注入)。Setter 方法注入还有一个好处就是可以使该类的属性可以在以后重新配置或重新注入。一些纯粹主义者喜欢基于构造函数的注入,这样意味着所有的属性都被初始化了,缺点则是对象变得不太适合重新配置和重新注入。另外在一些特殊的场景下,如一个第三方类要注入到 Spring 容器,但是该类没有提供 set 方法,那么此时你就只能使用构造方法注入了。

    英文水平有限,大概翻译了下。小伙伴们重点看加粗部分,也就是说在 Spring3.0 时代,官方还是提倡 set 方法注入的。

    不过从 Spring4.x 开始,官方就不推荐这种注入方式了,转而推荐构造器注入。

    我们来看看 Spring4.x 的文档怎么说(https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/htmlsingle/#beans-setter-injection):

    这段内容我就不一一翻译了,大家重点看第二段第一句:

    The Spring team generally advocates constructor injection

    这句话就是说 Spring 团队倡导通过构造方法完成注入。才一个大版本更新,Spring 咋就变了呢?别急,人家也给出用构造方法注入的理由,第二段翻译一下大概是这个意思:

    通过构造方法注入的方式,能够保证注入的组件不可变,并且能够确保需要的依赖不为空。此外,构造方法注入的依赖总是能够在返回客户端(组件)代码的时候保证完全初始化的状态。

    上面这段话主要说了三件事:

    1. 依赖不可变:这个好理解,通过构造方法注入依赖,在对象创建的时候就要注入依赖,一旦对象创建成功,以后就只能使用注入的依赖而无法修改了,这就是依赖不可变(通过 set 方法注入将来还能通过 set 方法修改)。

    2. 依赖不为空:通过构造方法注入的时候,会自动检查注入的对象是否为空,如果为空,则注入失败;如果不为空,才会注入成功。

    3. 完全初始化:由于获取到了依赖对象(这个依赖对象是初始化之后的),并且调用了要初始化组件的构造方法,因此最终拿到的就是完全初始化的对象了。

    在 Spring3.0 文档中,官方说如果构造方法注入的话,属性太多可能会让代码变得非常臃肿,那么在 4.0 文档中,官方对这个说法也做了一些订正:如果用构造方法注入的时候,参数过多以至于代码过于臃肿,那么此时你需要考虑这个类的设计是否合理,这个类是否参杂了太多的其他无关功能,这个类是否做到了单一职责。

    好吧,你说的总是有理!

    这是构造方法注入和 set 方法注入的问题,那么上面我们还提到不推荐属性注入,这又是咋回事呢?

    属性注入其实有一个显而易见的缺点,那就是对于 IOC 容器以外的环境,除了使用反射来提供它需要的依赖之外,无法复用该实现类。因为该类没有提供该属性的 set 方法或者相应的构造方法来完成该属性的初始化。换言之,要是使用属性注入,那么你这个类就只能在 IOC 容器中使用,要是想自己 new 一下这个类的对象,那么相关的依赖无法完成注入。

    以上分析都是根据 Spring 官方文档得来,日常开发应该还是属性注入较多,这个咱们不必纠结,代码该咋写还咋写,Spring 官方的态度了解一下即可,当然,如果项目允许,也不妨试试 Spring 推荐的代码规范。

    3. 小结

    好啦,今天就和小伙伴们随便扯扯 Spring 中的注入方式,希望对你有帮助~

    展开全文
  • 本篇文章主要介绍了详解Spring通过@Value注解注入属性的几种方式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
  • Spring注入bean的几种方式

    千次阅读 2021-10-04 10:38:56
    当我们想要将组件注入Spring的IOC容器中,除了@Controller、@Service、@Repository、@Component,还有一些常用的方法,下面我就这些方法简单的介绍下。 ps:下面所有的输出都是基于以下代码: public void testBean...
  • Spring注入Bean的几种方式

    千次阅读 2020-03-18 17:18:13
    Spring注入Bean的几种方式 通过注解注入Bean 使用xml文件,一个一个的注入,就例如下面这样 <bean id="bean" class="beandemo.Bean" /> xml扫描包的方式 <context:component-scan base-package=...
  • 主要介绍了Spring注入Date类型的三种方法总结的相关资料,希望通过本文能帮助到大家,让大家掌握这几种方法,需要的朋友可以参考下
  • Spring实现依赖注入几种方式 1.基于有参构造实现 <bean id="user" class="com.ccu.twj"> <constructor-arg name="name" value="张三"></constructor-arg> <constructor-arg name="age" ...
  • Spring注入bean的常用的六种方式

    千次阅读 2022-03-02 10:50:06
    Spring注入bean的常用的六种方式
  • Spring往容器中注入组件四种方式: 1. 包扫描(@ComponentScan+@Controller,@Service,@Component,@Repository) 开发中经常使用。 2. 配置类 @Configuration + @Bean方式 一般用导入第三方的组件 3. 使用@Import...
  • spring种注入方式

    千次阅读 2021-10-20 14:56:26
    一个接口有多个实现被spring管理吗,在依赖注入式,spring会不知道注入哪个实现类就会抛出NoUniqueBeanDefinitionException异常 使用@Primary 来告诉Spring 注入哪个实现类 Qualifier @ComponentScan不同的配置对...
  • Spring 注入 Bean 的七种方式

    千次阅读 2021-09-01 00:05:40
    来源:juejin.cn/post/6844903813753602056通过注解注入Bean背景我们谈到Spring的时候一定会提到IOC容器、DI依赖注入Spring通过将一个个类标...
  • Spring种注入对象的方式对比

    千次阅读 多人点赞 2022-04-15 10:53:21
    获取 bean 对象也叫做对象装配,是把对象取出来...Spring注入方式属性注入setter注入构造方法注入种注入方式对比 公共类: package com.bit.Model; /** * 表示一个实体类,不存在Spring当中 */ public class Us.
  • Spring自动注入几种方式

    千次阅读 2019-06-25 16:58:00
    ---恢复内容开始--- @Service("accountEmailService")public class AccountEmailServiceImpl implements ... /** 通过构造器注入---begin **/ private JavaMailSender javaMailSender; @Auto...
  • 主要介绍了浅谈spring ioc的注入方式注入不同的数据类型,具有一定借鉴价值,需要的朋友可以参考下
  • Spring支持两依赖注入方式,分别是属性注入和构造函数注入、除此之外,spring还支持工厂方法注入方式。 属性注入 属性注入指通过setXxx()方法注入Bean的属性值或依赖对象。由于属性注入方式具有可选择性和灵活...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 95,300
精华内容 38,120
关键字:

spring注入的几种方式

spring 订阅