Spring的自动注入总结

相信一说到spring的自动注入作为Java程序员应该非常的熟悉,但是你对spring自动注入有没有深入的理解呢

首先所谓的自动注入也可以称之为自动装配,spring除了自动装配,还可以手动装配,下面通过Xml来看看一个手动装配的例子吧

package com.xp.service;

public class HelloService {

    private ZullService zullService;

    public void query(){
        System.out.println(zullService);
    }
}
package com.xp.service;

public class ZullService {
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byType">

    <bean id="helloService"
          class="com.xp.service.HelloService">
        <property name="zullService">
           <ref bean="zullService" />
       </property>
    </bean>

    <bean id="zullService" class="com.xp.service.ZullService">
    </bean>
</beans>

上面的这个例子就是一个常见的手动装配的例子,但是在我们实际的开发过程中,很少会这么去用,因为比较繁琐,如果项目需要管理的Bean很多,这样一个一个的配置,很麻烦。Spring有两种主要的依赖注入的方式,官网上面有过说明,分为通过构造器注入,还有是通过set方式注入。那么对于现在Spirng开发主要用的是注解版的方式,我们在项目中是通过常用注解@Autowired的方式进行注入的,那么这种方式究竟是根据什么形式注入的呢,Spring装配模型有四种类,第一种 NO,第二种 ByType,第三中ByName ,第四种 构造器,那么@Autowired是如何注入的呢?看一下下一个例子

package com.xp.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HelloService {
    @Autowired
    private ZullService zullService;

    public void setZullService(){
        System.out.println("通过set方式注入");
    }

    public void query(){
        System.out.println(zullService);
    }
}
package com.xp.service;

import org.springframework.stereotype.Component;

@Component
public class ZullService {
}
package com.xp.test;

import com.xp.config.AppConfig;
import com.xp.dao.IndexDao;
import com.xp.service.HelloService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIoc {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        HelloService helloService = context.getBean(HelloService.class);
        helloService.query();

        /*ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
        xmlApplicationContext.getBean(HelloService.class).query();
*/
    }
}

从代码上面看如何@Autowired是通过set方式注入的话,肯定会执行这个setZullService的方法,但执行结果并没有执行这个set方法

Spring的自动注入总结

其实通过@Autowre方式注入,其实也是基于set方式的一种变体,看spring的源码其实是通过后置处理器通过反射拿到变量field.set的方式注入的,还有spring的set注入其实是不需要属性的,只要提供一个set方法就可以了,接着看下面的例子

package com.xp.service;



public class HelloService {

    private ZullService zullService;

    public void setA(ZullService zullService){
        this.zullService = zullService;
        System.out.println("通过set方式注入");
    }

    public void query(){
        System.out.println(zullService);
    }
}
package com.xp.service;
public class ZullService {
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byType">

    <bean id="helloService"
          class="com.xp.service.HelloService">
    </bean>

    <bean id="zullService" class="com.xp.service.ZullService">
    </bean>
</beans>
package com.xp.test;

import com.xp.config.AppConfig;
import com.xp.dao.IndexDao;
import com.xp.service.HelloService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIoc {
    public static void main(String[] args) {
      /*  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        HelloService helloService = context.getBean(HelloService.class);
        helloService.query();*/

        ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");
        xmlApplicationContext.getBean(HelloService.class).query();

    }
}

Spring的自动注入总结

 

通过执行结果,可以看出来在HelloService里面通过setA方法完成了ZullService的注入,明显看出来这spirng的set方式注入是不需要属性的,这里引申出一个问题就是@Autowire到底是通过我们spring的装配模型的哪种完成注入的呢,因为spring官网有说明自动装配有四种模型分表是no、bytype、byname、constructor;网上有说@Autowre是通过byType完成注入的,也就是默认的@Autowire是自动装配并且装配模型是byType,但是我觉得这种说法是有问题的,看下面的例子

package com.xp.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@Configuration
@ComponentScan(value = "com.xp")
@ImportResource(value = "spring.xml")
public class AppConfig {
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byType">

    <bean id="helloService"
          class="com.xp.service.HelloService">
    </bean>

    <bean id="zullService" class="com.xp.service.ZullService">
    </bean>
</beans>
package com.xp.service;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostprocessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
      GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) configurableListableBeanFactory.getBeanDefinition("helloService");

        System.out.println("自动装配的模式:" + genericBeanDefinition.getAutowireMode());
    }
}
package com.xp.test;

import com.xp.config.AppConfig;
import com.xp.dao.IndexDao;
import com.xp.service.HelloService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIoc {
    public static void main(String[] args) {
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        HelloService helloService = context.getBean(HelloService.class);
        helloService.query();

    }
}

Spring的自动注入总结

通过自定义一个BeanFactoryPostprocessor后置处理器,通过TestIoc运行程序,可以看到此时bean的装配模式是2,也就是byType 和 spring.xml配置的default-autowire="byType"是匹配上的。当我们用@Autowrie来进行注入的时候,我们看看执行结果

 

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HelloService {

    @Autowired
    private ZullService zullService;

    public void setA(ZullService zullService){
        this.zullService = zullService;
        System.out.println("通过set方式注入");
    }

    public void query(){
        System.out.println(zullService);
    }
}
package com.xp.service;


import org.springframework.stereotype.Component;

@Component
public class ZullService {
}
package com.xp.service;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostprocessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
      GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition) configurableListableBeanFactory.getBeanDefinition("helloService");

        System.out.println("自动装配的模式:" + genericBeanDefinition.getAutowireMode());
    }
}
package com.xp.test;

import com.xp.config.AppConfig;
import com.xp.dao.IndexDao;
import com.xp.service.HelloService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestIoc {
    public static void main(String[] args) {
       AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        HelloService helloService = context.getBean(HelloService.class);
        helloService.query();

    }
}

Spring的自动注入总结

改成注解方式可以看出这个执行结果装配模式是0 也就默认的NO类型,所以说@Autowire和自动装配模型是两个不同概念,@Autowire是通过注解的方式进行注入,在后置处理器进行解析和注入,而byType是自动装配模型,两者是不一样的,两者没什么关系