注入作为Spring最大的武器,已经在java代码中遍地开花。注入的方式也从最原始的set、构造器发展到现在的注解、自动扫描等高科技,为了让大家了解Spring的历史,这里也来聊聊IOC。
(1)首先是set注入,需要做两件事:配置property,实现set方法,代码如下
<bean class="com.alibaba.dubbo.demo.consumer.DemoAction" init-method="start"> <property name="anotherUserRestService" ref="anotherUserRestService" /> </bean>
public class DemoAction { private AnotherUserRestService anotherUserRestService;
public void setAnotherUserRestService(AnotherUserRestService anotherUserRestService) { this.anotherUserRestService = anotherUserRestService; } public void start() throws Exception { User user = new User(1L, "larrypage"); System.out.println("SUCCESS: registered user with id " + anotherUserRestService.registerUser(user).getId()); System.out.println("SUCCESS: got user " + anotherUserRestService.getUser(1L)); } }
这里要注意set后面带的名称,需要与property的name属性anotherUserRestService保持一致,也就是setXXX的XXX必须是配置文件中property的name值。
(2)构造器注入也只要做两件事:配置constructor-arg,实现构造器,看代码
<bean id="envConfig" class="cn.hello.millet.EnvConfig"> <constructor-arg type="java.lang.String" value="${app.name}" /> <constructor-arg type="java.lang.String" value="${app.env}" /> <constructor-arg type="java.lang.String" value="${hostname}" /> </bean>
public EnvConfig(String appname, String env, String hostname){ this.appname = appname; this.type = EnvType.getEnvType(env); this.initHostname(hostname); }
构造器注入还发展出了索引技术,利用index而不是type来区分构造器入参,如下
<bean id="ms.common.msDemoConsumer.consumer" class="cn.hello.newportal.pg.etcd.consumer.DemoPageConsumer" init-method="init"> <constructor-arg index="0" type="cn.hello.millet.MilletContext" ref="milletContext" /> <constructor-arg index="1" value="${version}" /> </bean>
(3)静态或者实例工厂的方法注入不常见,不过原理都是相同的,重点是后面的“方法”,也就是bean的注入是从“方法”调用来获取的,这里不举例,具体可以参见使用Spring的StingUtils的commaDelimitedListToStringArray来获取字符串数组
(4)注解注入有@Autowired、@Resource、@Component、@Repository、@Service、@Controller,其中最常用的就是@Autowired,使用它有两个前提:一个是必须支持注解,另一个就是被注入的是IOC里的bean,看代码
<context:annotation-config />
<bean id="zoneResourceService"
class="com.hello.zoneresource.provider.dao.ZoneResourceServiceImpl" />
public class MobileZoneResourceServiceImpl implements MobileZoneResourceService
{
@Autowired
private ZoneResourceService zoneResourceService;
public List<Map<String, Object>> queryCityList(String param)
{
BpmUserInfo userinfo = (BpmUserInfo)JsonUtil.getObject4JsonString(param, BpmUserInfo.class);
List<Map<String, Object>> cityList = zoneResourceService.queryCityList(userinfo);
return cityList;
}
}
上面是在配置文件中加的“<context:annotation-config />”就是为了获取注解的能力,有了@Autowired,zoneResourceService这个bean无需再通过set或者构造器注入。我们也可以通过@Component、@Repository、@Service或@Controller来注入bean到IOC,然后通过@Autowired来引入这个bean。只不过为了能够发现那4个注解,这时需要获取自动扫描的能力。
把“<context:annotation-config />”改为“<context:component-scan base-package="ms.migu.cache" />”即可,这样就能扫描ms.migu.cache包路径下所有的带有@Component、@Repository、@Service或@Controller的类,发现了就注册到IOC容器中。这里需要注意context:component-scan同时具有注册、发现bean的功能,而context:annotation-config只能发现,所以前者包含了后者,如果配置了前者,那就可以不配置后者。
@Resource跟@Autowired差不多的作用,也是用来引入bean,只不过默认是根据名称来,而@Autowired是根据对象类型来。看代码
<context:component-scan base-package="ms.hello.cache" />
package ms.hello.cache;
@Service
public class GetDetailMsgsMethodImpl
{
public void init()
{
super.initialize(GetDetailMsgsMethodImpl.class);
}
}
public class MessageDetailServiceImpl { @Autowired private GetDetailMsgsMethodImpl getDetailMsgsMethodImpl; public void init() { getDetailMsgsMethodImpl.init(); } }
把MessageDetailServiceImpl改成这样是ok的
public class MessageDetailServiceImpl { @Resource private GetDetailMsgsMethodImpl getDetailMsgsMethodImpl; public void init() { getDetailMsgsMethodImpl.init(); } }
上面的例子里没有指定具体value值,那么@Service默认使用@Service(value="getDetailMsgsMethodImpl")进行bean注册,而@Resource默认按@Resource(name="getDetailMsgsMethodImpl")来注入。如果注入的是接口,而实现类有多个,那么@Autowired需要用到@Qualifier注解来区分实现类的类名。假如GetDetailMsgsMethod是个接口,实现类有GetDetailMsgsMethodImplA和GetDetailMsgsMethodImplB,那在注入接口时必须要指明实现类的名称
public class MessageDetailServiceImpl { @Autowired @Qualifier("GetDetailMsgsMethodImplB") private GetDetailMsgsMethod getDetailMsgsMethod; public void init() { getDetailMsgsMethod.init(); } }
上面代码还有一个前提,就是GetDetailMsgsMethodImplB必须也注册到IOC中才能使用@Qualifier引入bean的名称。
@Component是通用注解,标注了它的类都会被注册到IOC容器,而@Repository适用于DAO层,@Service适用于业务层,@Controller适用于web层。但如果使用@Controller不仅仅只是为了注册到IOC,还想作为Spring MVC的controller用于分发web请求的话,那么还需要配置mvn驱动<mvc:annotation-driven />。