简介

spring中将java对象称为bean,装配bean的三种方式

  • 隐式的bean发现机制和自动装配(企业主流)
  • 在java中进行显示的配置
  • 在xml中进行显示的配置

1. 隐式的bean发现机制和自动装配

  • 组建扫描
    • @Component:表示这个类需在应用程序中被创建
    • @ComponentScan:自动发现应用程序中创建的类
  • 自动装配
    • @Autowired:自动满足bean之间的依赖
  • 定义配置类
    • @Configuration:表示当前类是一个配置类

1.1创建项目

和之前一样

1.2使用配置类

当没有main方法时,如何测试?

创建配置类,将@componentscan与main方法解耦

  1. package soundsystem;
  2. import org.springframework.context.annotation.ComponentScan;
  3. import org.springframework.context.annotation.Configuration;
  4. /**
  5. *Spring程序配置类
  6. */
  7. @ComponentScan
  8. @Configuration
  9. public class AppConfig {
  10. }

1.3使用junit4单元测试

普通创建模式

  1. pom.xml中添加依赖
    1. <dependency>
    2. <groupId>junit</groupId>
    3. <artifactId>junit</artifactId>
    4. <version>4.12</version>
    5. </dependency>

2.在test中创建一个和java文件夹下一样的文件结构,并创建测试类
1551084967062.png

package soundsystem;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {
    @Test
    public void testPlay(){
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        CDPlayer player = context.getBean(CDPlayer.class);
        player.play();
    }
}

spring创建模式

  • 引入Spring单元测试mokuai
    • maven : junit、spring-test
    • @RunWith(SpringJUnit4ClassRunner.class)
  • 加载配置类
  1. pom.xml中加入依赖

    <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-test</artifactId>
             <version>4.3.13.RELEASE</version>
         </dependency>
    
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
         </dependency>
    
  2. 2.在test中创建一个和java文件夹下一样的文件结构,并创建测试类

package soundsystem;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class AppTest {
    @Autowired
    private CDPlayer player;

    @Test
    public void testPlay(){
        player.play();
    }
}

1.4Autowired使用场景

  1. 构造函数进行依赖注入(效率最高)

    @Autowired
     public CDPlayer(CompactDisc cd, Power power) {
         this.cd = cd;
         this.power = power;
         System.out.println("CDPlayer的多参数构造函数。。。");
     }
    
  2. 成员变量进行依赖注入(最便捷的方式)

    @Autowired
     private CompactDisc cd;
     @Autowired
     private Power power;
    
  3. set方法进行依赖注入

    @Autowired
     public void setCd(CompactDisc cd) {
         this.cd = cd;
         System.out.println("调用setcd...");
     }
    
     @Autowired
     public void setPower(Power power) {
         this.power = power;
         System.out.println("调用setPOWER...");
     }
    
  4. 在任意方法进行依赖注入

    @Autowired
     public void prepare(CompactDisc cd,Power power){
         this.cd = cd;
         this.power = power;
         System.out.println("prepare方法被调用。。。");
     }
    

1.5 required

  • @Autowired(required=false)
  • 表示注入方式是可选的

1.6 使用接口

有两点注意:

  1. @Component写在实现类中,而不是接口
  2. 申请接口的成员变量

1.7 自动装配的歧义性

当有两个类实现了同一个接口的同一个方法时会产生歧义

package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.stereotype.Component;

@Component
public class UserServiceNormal implements UserService {

    public void add() {
        System.out.println("添加用户");
    }
}
package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.stereotype.Component;

@Component
public class UserServiceFestival implements UserService {
    public void add() {
        System.out.println("注册用户并发送优惠劵");
    }
}
package com.qfen.demo.service;

import com.qfendu.demo.service.AppConfig;
import com.qfendu.demo.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
    @Autowired
    private UserService userService;
    @Test
    public void testAdd(){
        userService.add();
    }
}

有两种方法解决:

1.7.1.声明变量时用实现类声明(并不好,没有面向接口)

1.7.2使用首选been

将要使用的实现类添加一个注解Primary

package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Component
@Primary
public class UserServiceFestival implements UserService {
    public void add() {
        System.out.println("注册用户并发送优惠劵");
    }
}

缺点:只能有一个首选bean,且是在实现类中添加的,后期不好更改

1.7.3使用限定符

1.7.3.1 在实现类中添加限定符注解@Qualifier(“ID”)

1.7.3.2 在测试类中的变量声明中添加限定符注解@Qualifier(“ID”)

package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("normal")
public class UserServiceNormal implements UserService {

    public void add() {
        System.out.println("添加用户");
    }
}
package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
@Qualifier("festival")
public class UserServiceFestival implements UserService {
    public void add() {
        System.out.println("注册用户并发送优惠劵");
    }
}
package com.qfen.demo.service;

import com.qfendu.demo.service.AppConfig;
import com.qfendu.demo.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
    @Autowired
    @Qualifier("normal")
    private UserService userService;
    @Test
    public void testAdd(){
        userService.add();
    }
}

1.7.4使用限定符和类ID(二)

1.7.4.1在实现类中的@Component后面添加id

1.7.4.2在测试类中添加@Qualifier(“ID”)

package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.stereotype.Component;

@Component("normal")
public class UserServiceNormal implements UserService {

    public void add() {
        System.out.println("添加用户");
    }
}
package com.qfen.demo.service;

import com.qfendu.demo.service.AppConfig;
import com.qfendu.demo.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
    @Autowired
    @Qualifier("normal")
    private UserService userService;
    @Test
    public void testAdd(){
        userService.add();
    }
}

1.7.5使用限定符和类ID(三)

实现类什么都不做,测试类添加@Qualifier(“ID”)

spring会给实现类一个默认ID,就是第一个字母小的类名

package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.stereotype.Component;

@Component
public class UserServiceNormal implements UserService {

    public void add() {
        System.out.println("添加用户");
    }
}
package com.qfen.demo.service;

import com.qfendu.demo.service.AppConfig;
import com.qfendu.demo.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
    @Autowired
    @Qualifier("userServiceNormal")
    private UserService userService;
    @Test
    public void testAdd(){
        userService.add();
    }
}

1551169835899.png

1.7.6 java标准的解决方案(一)

测试类中给变量添加注解Resource(name = “ID”),不要Autowired

Resource(name = “ID”)相当于@Autowired加@Qualifier(“ID”),这个不是spring的标准中的内容,是jdk标准中的内容

package com.qfen.demo.service;

import com.qfendu.demo.service.AppConfig;
import com.qfendu.demo.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
//    @Autowired
//    @Qualifier("userServiceNormal")
    @Resource(name = "userServiceNormal")
    private UserService userService;
    @Test
    public void testAdd(){
        userService.add();
    }
}

1.7.7 java标准的解决方案(二)

基本和1.7.5相同,@Resource也可以使用自定义ID

package com.qfendu.demo.service.impl;

import com.qfendu.demo.service.UserService;
import org.springframework.stereotype.Component;

@Component("ff")
public class UserServiceFestival implements UserService {
    public void add() {
        System.out.println("注册用户并发送优惠劵");
    }
}
package com.qfen.demo.service;

import com.qfendu.demo.service.AppConfig;
import com.qfendu.demo.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class UserServiceTest {
//    @Autowired
//    @Qualifier("userServiceNormal")
    @Resource(name = "ff")
    private UserService userService;
    @Test
    public void testAdd(){
        userService.add();
    }
}

1.8 处理分层架构

用于区分个层的注解

web层 Controller

service层 Service

dao层 Repository

这三个都可以代替@Component,作用没有区别,只是语义上进行区别

1.9设置组件扫描的基础包

@ComponentScan

默认情况下只扫描本包(文件夹),添加路径可以扫描路径下所有的包

@ComponentScan("com.qfendu.demo")

使用basePackages,可以像数组一样添加多个包(有缺陷,修改包名后,这里也需要修改)

@ComponentScan(basePackages = {"com.qfendu.demo.web","com.qfendu.demo.dao"})

使用basePackageClasses,可以像数组一样添加多个类(比方法二更安全)

@ComponentScan(basePackageClasses = {UserController.class, UserService.class, UserDao.class})

1.10 使用xml启用组件扫描

新建一个applicationContext.xml文件,在里面添加路径

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--添加路径-->
    <context:component-scan base-package="com.qfendu.demo"/>


</beans>

1.11 总结

image.png