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方法
其实通过@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(); } }
通过执行结果,可以看出来在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(); } }
通过自定义一个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(); } }
改成注解方式可以看出这个执行结果装配模式是0 也就默认的NO类型,所以说@Autowire和自动装配模型是两个不同概念,@Autowire是通过注解的方式进行注入,在后置处理器进行解析和注入,而byType是自动装配模型,两者是不一样的,两者没什么关系