注入作为Spring最强大的武器,已经在java代码中遍地开花。注入的方式也从最原始的set、构造器等鸟枪发展到现在的注解、自动扫描等高科技大炮了。这里也来聊聊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="com.hello.WlfConfig">
<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 WlfConfig(String appname, String env, String hostname){
this.appname = appname;
this.type = EnvType.getEnvType(env);
this.initHostname(hostname);
}
构造器注入还发展出了索引技术,利用index而不是type来区分构造器入参,如下
<bean id="wlf.hello.demoConsumer.consumer" class="wlf.hello.consumer.DemoConsumer"
init-method="init">
<constructor-arg index="0" type="com.hello.HelloContext"
ref="helloContext" />
<constructor-arg index="1" value="${version}" />
</bean>
(3)静态或者实例工厂的方法注入不常见,不过原理都是相同的,重点是后面的“方法”,也就是bean的注入是从“方法”调用来获取的
(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="com.wlf.hello" />”即可,这样就能扫描com.wlf.hello包路径下所有的带有@Component、@Repository、@Service或@Controller的类,发现了就注册到IOC容器中。这里需要注意context:component-scan同时具有注册、发现bean的功能,而context:annotation-config只能发现,所以前者包含了后者,如果配置了前者,那就可以不配置后者。
@Resource跟@Autowired差不多的作用,也是用来引入bean,只不过它默认是根据名称来,而@Autowired是根据对象类型来。看代码
<context:component-scan base-package="com.wlf.hello" />
package com.wlf.hello;
@Service
public class GetHelloMethodImpl
{
public void init()
{
super.initialize(GetDetailMsgsMethodImpl.class);
}
}
public class MessageDetailServiceImpl
{
@Autowired
private GetHelloMethodImpl getHelloMethodImpl;
public void init()
{
getHelloMethodImpl.init();
}
}
把MessageDetailServiceImpl改成这样是ok的
public class MessageDetailServiceImpl
{
@Resource
private GetHelloMethodImpl getHelloMethodImpl;
public void init()
{
getHelloMethodImpl.init();
}
}
上面的例子里没有指定具体value值,那么@Service默认使用@Service(value="getHelloMethodImpl")进行bean注册,而@Resource默认按@Resource(name="getHelloMethodImpl")来注入。如果注入的是接口,而实现类有多个,那么@Autowired需要用到@Qualifier注解来区分实现类的类名。假如GetHelloMethodImpl是个接口,实现类有GetHelloMethodImplA和GetHelloMethodImplB,那在注入接口时必须要指明实现类的名称
public class MessageDetailServiceImpl
{
@Autowired
@Qualifier("GetHelloMethodImplB")
private GetHelloMethod getHelloMethod;
public void init()
{
getHelloMethod.init();
}
}
上面代码还有一个前提,就是GetDetailMsgsMethodImplB必须也注册到IOC中才能使用@Qualifier引入bean的名称。
@Component是通用注解,标注了它的类都会被注册到IOC容器,而@Repository适用于DAO层,@Service适用于业务层,@Controller适用于web层。但如果使用@Controller不仅仅只是为了注册到IOC,还想作为Spring MVC的controller用于分发web请求的话,那么还需要配置mvn驱动<mvc:annotation-driven />。