Spring自动注入

谈及一个问题,无非牵扯到三点,是什么,怎么来的,怎么用的

Spring自动注入是什么

是指容器中的一个组件中需要用到另一个组件(例如聚合关系)时,依靠spring容器创建对象,而不是手动创建;

Spring自动注入怎么来的

在这里就要提及一种设计思路,在以往,我们很多都是从上到下的描写代码,先写顶层,然后在逐步更改底层,但是这样会出现一种情况,如果底层的某个代码需要更改,那么出现的问题就是整个代码都要更改。所以,为了避免这种情况,我们会采用新的设计模式,依赖倒置模式,也就是从底层出发,然后再依次搭建顶层,而为了实现这一设计模式,自动注入就出现了

依赖倒置原则

方法就是用的依赖注入方法

思路控制反转

Spring自动注入怎么用的

Spring通过DI(依赖注入)实现IOC(控制反转),常用的注入方式主要有三种:

(1)基于注解的注入。

(2)构造方法注入。

(3)setter注入,

1、创建一个模拟DAO层类:UserTestDao。用于测试依赖注入。其源码如下:

public class UserTestDao {

public boolean login(){
    System.out.println("UserTestDao.login()");
    return true;
}

}
2.1 基于注解的注入-自动装配模式
2.1.1 bean标签的autowire属性
在介绍注解注入的方式前,先了解bean的一个属性autowire。

autowire属性有5种模式:

(1)no

(默认)不采用autowire机制.。这种情况,当我们需要使用依赖注入,只能用标签。

(2)byName

通过属性的名称自动装配(注入)。Spring会在容器中查找名称与bean属性名称一致的bean,并自动注入到bean属性中。当然bean的属性需要有setter方法。例如:bean A有个属性master,master的setter方法就是setMaster,A设置了autowire=“byName”,那么Spring就会在容器中查找名为master的bean通过setMaster方法注入到A中。

(3)byType

通过类型自动装配(注入)。Spring会在容器中查找类(Class)与bean属性类一致的bean,并自动注入到bean属性中,如果容器中包含多个这个类型的bean,Spring将抛出异常。如果没有找到这个类型的bean,那么注入动作将不会执行。

(4)constructor

类似于byType,但是是通过构造函数的参数类型来匹配。假设bean A有构造函数A(B b, C c),那么Spring会在容器中查找类型为B和C的bean通过构造函数A(B b, C c)注入到A中。与byType一样,如果存在多个bean类型为B或者C,则会抛出异常。但时与byType不同的是,如果在容器中找不到匹配的类的bean,将抛出异常,因为Spring无法调用构造函数实例化这个bean。

(5)default

采用父级标签(即beans的default-autowire属性)的配置。

2.1.2 使用注解注册bean
有四种注解可以注册bean,每种注解可以任意使用,只是语义上有所差异:

(1)@Component:可以用于注册所有bean

(2)@Repository:主要用于注册dao层的bean

(3)@Controller:主要用于注册控制层的bean

(5)@Service:主要用于注册服务层的bean

这些都是注解在平时的开发过程中出镜率极高,@Component、@Repository、@Service、@Controller实质上属于同一类注解,用法相同,功能相同,区别在于标识组件的类型。@Component可以代替@Repository、@Service、@Controller,因为这三个注解是被@Component标注的。

2.1.3 装配bean时常用的注解
2.1.3.1 @Resource
1、 @Resource是默认以byName的方式去匹配与属性名相同的bean的id。

如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。

2、 @Resource不属于spring的注解,而是Java的注解,它来自于JSR-250位于java.annotation包下,使用该annotation为目标bean指定协作者Bean。

  • @Resource注解的定义:

@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default “”;
Class type() default java.lang.Object.class;

使用demo

public class AnotationExp {

@Resource(name = "HappyClient")
private HappyClient happyClient;

@Resource(type = HappyPlayAno.class)
private HappyPlayAno happyPlayAno;

}
2.1.3.2 @Autowired
1、使用@Autowired注解来自动装配指定的bean。

2、在使用@Autowired注解之前需要在Spring配置文件进行配置,<context:annotation-config />。在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性。在使用@Autowired时,首先在容器中查询对应类型的bean:

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据;

  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找;

  • 如果上述查找的结果为空,那么会抛出异常。解决方法时,使用required=false。

3、@Autowired属于Spring 的org.springframework.beans.factory.annotation包下,可用于为类的属性、构造器、方法进行注值。

- @Autowired注解的定义:

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}
使用demo:

@Controller
public class HappyController {
    @Autowired //默认依赖的ClubDao 对象(Bean)必须存在
    //@Autowired(required = false) 改变默认方式
    @Qualifier("goodClubService")
    private ClubService clubService;
 
    // Control the people entering the Club
    // do something
}

2.1.3.3 @Autowired和@Resource的总结
1、相同点

@Resource的作用相当于@Autowired,均可标注在字段或属性的setter方法上。

2、不同点

(1)提供方

@Autowired是Spring的注解;@Resource是javax.annotation注解,而是来自于JSR-250,J2EE提供,需要JDK1.6及以上。

(2)注入方式

@Autowired只按照Type 注入;@Resource默认按Name自动注入,也提供按照Type 注入;

(3)属性

@Autowired注解可用于为类的属性、构造器、方法进行注值。

默认情况下,其依赖的对象必须存在(bean可用),如果需要改变这种默认方式,可以设置其required属性为false。

还有一个比较重要的点就是,@Autowired注解默认按照类型装配,如果容器中包含多个同一类型的Bean,那么启动容器时会报找不到指定类型bean的异常,解决办法是结合@Qualified注解进行限定,指定注入的bean名称。

@Resource有两个中重要的属性:name和type。name属性指定byName,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。

需要注意的是:

  • @Resource如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时, @Resource注解会回退到按类型装配。但一旦指定了name属性,就只能按名称装配了。

  • @Resource注解的使用性更为灵活,可指定名称,也可以指定类型 ;

  • @Autowired注解进行装配容易抛出异常,特别是装配的bean类型有多个的时候,而解决的办法是需要在增加@Qualitied进行限定。

2.2 构造方法注入
创建一个模拟Service类:UserTestServiceImpl。源码如下:

public class UserTestServiceImpl {
 
    private UserTestDao userTestDao;
    /**
     * 如果只有一个有参数的构造方法并且参数类型与注入的bean的类型匹配,那就会注入到该构造方法中。
     *
     * @param userTestDao
     */
    public UserTestServiceImpl(UserTestDao userTestDao) {
        this.userTestDao = userTestDao;
    }
 
    public void login() {
        System.out.println("UserTestServiceImpl.login()");
        userTestDao.login();
    }
 
}

1、在spring的配置文件中注册UserTestServiceImpl,将UserTestDao 通过constructor-arg标签注入到UserTestServiceImpl的某个有参数的构造方法。spring配置如下:

<

!--dao -->
<bean id="userTestDao" class="com.chenlw.java.web.utils.springwiki.UserTestDao">
</bean>
 
<!-- 注册userService -->
<bean id="userTestServiceImpl" class="com.chenlw.java.web.utils.springwiki.UserTestServiceImpl">
    <!-- 将DAO对象注入Service-->
    <constructor-arg ref="userTestDao"/>
</bean>

2、测试代码:

@Test
public void testSpringInjection() {
    // 获取Service实例
    UserTestServiceImpl userTestService = (UserTestServiceImpl) applicationContext.getBean("userTestServiceImpl");
    // 模拟业务方法
    userTestService.login();
}

3、运行结果:

UserTestServiceImpl.login()
UserTestDao.login()

2.3 setter注入
1、修改UserTestServiceImpl类。源码如下:

public class UserTestServiceImpl {
 
    private UserTestDao userTestDao;
 
    public UserTestDao getUserTestDao() {
        return userTestDao;
    }
    /**
    * setter注入,该setter方法不可缺少,否则会注入失败。
    */
    public void setUserTestDao(UserTestDao userTestDao) {
        this.userTestDao = userTestDao;
    }
    public void login() {
        System.out.println("UserTestServiceImpl.login()");
        userTestDao.login();
    }
 
}

2、spring配置如下:

<!-- 注册dao -->
<bean id="userTestDao" class="com.chenlw.java.web.utils.springwiki.UserTestDao">
</bean>
 
<!-- 注册userService -->
<bean id="userTestServiceImpl" class="com.chenlw.java.web.utils.springwiki.UserTestServiceImpl">
    <!-- 将DAO对象注入Service-->
    <property name="userTestDao" ref="userTestDao"/>
</bean>

注意:

  • spring会将name值的每个单词首字母转换成大写,然后再在前面拼接上"set"构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入。

  • name属性值与类中的成员变量名以及set方法的参数名都无关,只与对应的set方法名有关。

3、测试代码:

@Test
public void testSpringInjection() {
    // 获取Service实例
    UserTestServiceImpl userTestService = (UserTestServiceImpl) applicationContext.getBean("userTestServiceImpl");
    // 模拟业务方法
    userTestService.login();
}

4、运行结果:

UserTestServiceImpl.login()
UserTestDao.login()
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值