Spring-framework @Autowired注入bean 为null之谜

环境:

JDK1.8

Spring-framework4.1.2.RELEASE

如下图所示的一个Spring javaSE工程

applicationContext.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">
  	
  	<context:component-scan base-package="com.chenjun.learnspring.annotation" />
  	
</beans>

TestInterface2内容:

package com.chenjun.learnspring.annotation;

public interface TestInterface2 {
	public void print();
}

TestInterfaceImpl2内容:

package com.chenjun.learnspring.annotation;

import org.springframework.stereotype.Service;

@Service
public class TestInterfaceImpl2 implements TestInterface2 {

	public void print() {
		System.out.println("TestInterfaceImpl2 is print");
	}

}

App.java内容: 

package com.chenjun.learnspring.annotation;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;


@Component
public class App {
	
	@Autowired
	private TestInterface2 testInterface2;

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		App app = new App();
		app.proxyPrint();
	}
	
	public void proxyPrint() {
		testInterface2.print();
	}

}

编译运行App.class主类

输出结果发现空指针异常,也就是说testInterface2的实现类并没有注入进来

Exception in thread "main" java.lang.NullPointerException

    at com.chenjun.learnspring.annotation.App.proxyPrint(App.java:24)

    at com.chenjun.learnspring.annotation.App.main(App.java:20)

 这是怎么回事呢,是因为testInterfaceImpl2这个类没有被Spring容器所管理吗? 

我打算输出一下Spring容器里面的bean一看究竟:

于是我编写如下代码:

略微修改之后的App.java

package com.chenjun.learnspring.annotation;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;


@Component
public class App {
	
	@Autowired
	private TestInterface2 testInterface2;

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		String[] beanArray = applicationContext.getBeanDefinitionNames();
		
		for(String s : beanArray) {
			System.out.println(s);
		}
		App app = new App();
		
		app.proxyPrint();
	}
	
	public void proxyPrint() {
		testInterface2.print();
	}

}

我把Spring容器里面现在的bean名称都打印一下,如下:

testInterfaceImpl2
app
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
Exception in thread "main" java.lang.NullPointerException
	at com.chenjun.learnspring.annotation.App.proxyPrint(App.java:31)
	at com.chenjun.learnspring.annotation.App.main(App.java:27)

从上面控制台输出信息可以看到,spring容器中确实已经有了testInterfaceImpl2,但是为什么上面声明这个bean的时候他没有注入呢?

原因就在于这行

App app = new App();

这行代码把App用new关键字进行创建对象,这就使得app依赖的其他bean已经脱离了spring的依赖注入管理

找到原因之后,最终我修改App.java的代码如下:

正确的注入方式

package com.chenjun.learnspring.annotation;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;


@Component
public class App {
	
	@Autowired
	private TestInterface2 testInterface2;

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		App app = applicationContext.getBean(com.chenjun.learnspring.annotation.App.class);
		app.proxyPrint();
	}
	
	public void proxyPrint() {
		testInterface2.print();
	}

}

 输出结果:

总结:

输出正常. 这也就说明了,spring在管理bean注入的策略是这样的:

当A组件依赖B, 要想使用spring依赖注入得到组件B的实例, 那么A本身也要是通过Spring的bean来创建的才行. 而不是直接new出A的实例;

猜你喜欢

转载自my.oschina.net/u/2338224/blog/1822135