经过spring注解(@Component)来代表该类会做为组件类,并告知Spring要为这类建立bean,不过组件扫描默认是不启动的,须要显式的配置Spring,从而命令Spring去寻找带有(@Component)注解的类,并为其建立bean。java
一、定义接口spring
package com.seven.springTest.service; public interface HelloWorldApi { public void sayHello(); }
二、定义接口的实现类api
package com.seven.springTest.service.impl; import org.springframework.stereotype.Component; import com.seven.springTest.service.HelloWorldApi; @Component //经过注解指定该类组件类,告知spring要为它建立Bean public class PersonHelloWorld implements HelloWorldApi { @Override public void sayHello() { System.out.println("Hello World,This Is Person!"); } }
三、前面说过了,spring并不能自动启用组件扫描,须要进行显式的配置,这里经过java类来进行显式的配置,定义java配置类HelloWorldConfig,在配置类中咱们没有显式的声明任何bean,只不过是使用了@CompontentScan注解来启用组件扫描数组
package com.seven.springTest; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan // 启用组件扫描 public class HelloWorldConfig { }
如今全部的工做已经完成,咱们来测试下ide
package com.seven.springTest.main; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.seven.springTest.HelloWorldConfig; import com.seven.springTest.service.HelloWorldApi; public class HelloWorldTest { public static void main(String[] args) { //1. 声明Spring上下文,采用java配置类 ApplicationContext ac = new AnnotationConfigApplicationContext(HelloWorldConfig.class); //2. 声明Spring应用上下文,采用xml配置 //ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml"); //经过Spring上下文获取Bean,在这里Spring经过自动扫描发现了PersonHelloWorld的实现,并自动建立bean。 HelloWorldApi hwapi = ac.getBean(HelloWorldApi.class); //经过sayHello()的输入内容能够看到,hwapi为PersonHelloWorld的实例 hwapi.sayHello(); } }
经过上的代码,在控制台会输出下面的内容 “Hello World,This Is Person!”函数
Spring容器经过组件扫描发现了PersonHelloWorld类,并为它建立了对应的bean。到此为止,咱们经过简单的注解实现自动化装配,在上面的案例中,HelloWorldConfig配置类@ComponentSan若是没有其余配置,只会扫描HelloWorldConfig所在包或者它的子包,若是须要制定扫描的包,能够经过工具
@ComponentScan("com.seven.springTest")
或者测试
@ComponentScan(basePackages="com.seven.springTest")
basePackages容许设置多个包,,只须要把basePackages熟悉设置成一个数组便可ui
@ComponentScan(basePackages={"com.seven.springTest.service","com.seven.springTest.impl"})
除了经过java配置类来设置Spring启用组件扫描,还可能经过xml类显式配置,参考下面xml配置,并在获取Spring应用上下文时经过xml来初始化。this
<?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" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <!-- 启用Spring组件扫描--> <context:component-scan base-package="com.seven.springTest"></context:component-scan> </beans>
在上面的案例中,咱们经过@Component和@ComponentScan来隐式的配置完成了Bean的装配工做,接下来咱们深刻的探讨下@Component和@ComponentScan
Spring容器在管理Bean的时候,会给每个Bean有一个ID标识,上面的例子,若是HelloWorldApi的实现类有多个,那么Spring容器该怎么分配Bean呢,若是咱们在使用@Component的时候,没有明确的给PersonHelloWorld设置一个ID,Spring容器会默认给bean给定一个ID,通常为类名(第一个字母会变为小写,例如跑personHelloWorld),因此下面的代码也是成立的
//经过bean的ID来获取实例 HelloWorldApi hwapi = (HelloWorldApi) ac.getBean("personHelloWorld"); hwapi.sayHello();
同时咱们也能够为bean设置ID,以下:
@Component("person") //为bean设置ID为“person” public class PersonHelloWorld implements HelloWorldApi { @Override public void sayHello() { // TODO Auto-generated method stub System.out.println("Hello World,This Is Person!"); } }
这样咱们在获取bean的时候就可经过ID来获取,以下:
// 根据设置的bean ID来获取bean HelloWorldApi hwapi = (HelloWorldApi) ac.getBean("person");
在以上的案例中咱们使用了@Component和@ComponentScan实现了组件扫描,目前为止咱们都是对单一的对象进行操做,若是程序复杂点,对象之间存在依赖,该如何处理呢?下面咱们就来研究下如何为bean添加注解实现自动装配
在上面的案例中Person对整个世界说了一句Hello,可说话只有旁边的人知道,咱们须要让更多的听到咱们的“hello world”,咱们就须要一些工具,咱们使用电视来广播就能让更多的人听到了,首先咱们定义一个传播工具接口
package com.seven.springTest.service; public interface TransmittingTool { void work(String message); }
接下来咱们来建立咱们的TV
package com.seven.springTest.service.impl; import org.springframework.stereotype.Component; import com.seven.springTest.service.TransmittingTool; @Component //设置为须要被扫描到的组件 public class TVTool implements TransmittingTool { @Override public void work(String message) { //传播工具工做,把咱们的消息传播出去 System.out.println(message); } }
接下来咱们须要对咱们以前的PersonHelloWorld的sayHello()方法进行一些修改,让它能够经过传播工具来对全世界说Hello
package com.seven.springTest.service.impl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.seven.springTest.service.HelloWorldApi; import com.seven.springTest.service.TransmittingTool; @Component public class PersonHelloWorld implements HelloWorldApi { //定义传播工具 @Autowired //1.直接变量添加注解 private TransmittingTool transmittingTool; // @Autowired //2. 经过构造函数注入依赖 // public PersonHelloWorld(TransmittingTool transmittingTool) { // this.transmittingTool = transmittingTool; // } // @Autowired //3. 经过属性的Setter方法注入依赖 // public void setTransmittingTool(TransmittingTool transmittingTool) { // this.transmittingTool = transmittingTool; // } // @Autowired //4. 经过其余函数注入依赖 // public void inserttool(TransmittingTool transmittingTool){ // this.transmittingTool=transmittingTool; // } @Override public void sayHello() { // 经过传播工具来sayHello transmittingTool.work("Hello World,This Is Person!--form TV"); } }
首先咱们定义了一个传播工具,这个工具的具体实现咱们不清楚,须要Spring容器去给我注入依赖。
@Autowired直接可使用在类变量、构造函数、Setter和其余任何方法上,参考代码中1-4的实现
若是可以配置到1个知足要求的依赖,那么这个被依赖的bean就会被装配进来,若是没有匹配的依赖bean,那么应用上下文建立的时候,Spring会抛出一个异常,为了不异常,咱们能够把@Autowired的required设置为false;
@Autowired(required=false) //2. 经过构造函数注入依赖 public PersonHelloWorld(TransmittingTool transmittingTool) { this.transmittingTool = transmittingTool; }
@Autowired的required设置给false后,Spring为尝试给bean自动装配,注入依赖,若是没有匹配的bean的话,Spring将会让这个bean处于未装配的状态,当时把required设置为false的时须要注意,由于这个依赖bean处于未装配状态,在调用依赖的时候,若是你的代码作null的检查,这个处于未装配状态的属性有可能会发生异常。
若是有多个bean能知足依赖关系的话,Spring也会抛出异常,代表没有明确指出选择哪一个bean进行自动装配。这个在后面我会单独开一篇讲解Spring的高级装配,到时候在详细说明,你们能够关注后续的文章。