相信一说到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是自动装配模型,两者是不一样的,两者没什么关系