目录
前情提要
我们上节内容学习了如何创建\注册\读取bean
 我们发现bean对象操作十分的繁琐!
 所以我们这个章节,就带大家来了解更加简单的bean操作,通过Spring下的注解来实现!
配置spring-config文件
我们可以直接在配置文件配置好 spring下你要注册对象的包时那个!
 当spring启动后,spring就会将bean对象自动注册!
- spring-config配置文件
<?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:content="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 https://www.springframework.org/schema/context/spring-context.xsd">
       <!--在com包下扫描bean注册-->
        <content:component-scan base-package="com"></content:component-scan>
</beans>
当然只有一个配置文件显然不够嘛!
 我们如何知道我们代码中的对象是bean对象捏?
 这就要引入spring五大注解概念了!
 我们通过在我们创建好的对象上面添加注解的方式,就是告诉spring这个对象需要注册到容器中!
类注解和方法注解
我们可以通过上述两种注解将对象存储到Spring中!
@Controller(控制器存储)
使用@Controller注解存储bean
package com;
import org.springframework.stereotype.Controller;
@Controller //通过Controller注解存储bean对象
public class UserController {
    public void sayHi(){
        System.out.println("hello Controller注解!");;
    }
}
我们通过在UserController类上加上spring类注解,即可完成注册对象!
- 在启动类中读取bean对象即可!
//启动类
public class app{
    public static void main(String[] args) {
        //1.获取上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        //读取bean对象!
        UserController userController =
                (UserController) context.getBean("userController");
        //使用
        userController.sayHi();
    }
}

 如果我们的需要注册的bean对象不在扫描包下,是否又能注册成功呢?
我们在新建一个controller包在其下创建TestController类,并且通过@Controller注册到Spring中!
package controller;
import org.springframework.stereotype.Controller;
@Controller //注册到Spring中!
public class TestController {
    public void sayHi(){
        System.out.println("该bean不在扫描的包下");
    }
}
然后我们通过ApplicationContext上下文对象读取bean
 
 可以看到出现异常未找到名为textController的bean对象!
结论:只有在扫描包下的类才能被Spring注册
@Service(服务存储)
注册bean
package com;
import org.springframework.stereotype.Service;
@Service // @Service 注解注册对象!
public class UserService {
    public  void sayHi(){
        System.out.println("Hello Service注解!");
    }
}
读取bean

@Configuration(配置存储)
package com;
import org.springframework.context.annotation.Configuration;
@Configuration //Configuration注解注册bean对象
public class UserConfiguration {
    public void sayHi(){
        System.out.println("Hello Configuration注解!");
    }
}

@Repository(仓库存储)
package com;
import org.springframework.stereotype.Repository;
@Repository //@Respository 注解注册对象
public class UserRepository {
    public void sayHi(){
        System.out.println("Hello Respository注解!");
    }
}

@Component(组件存储)
package com;
import org.springframework.stereotype.Component;
@Component //Component注解注册对象!
public class UserComponent {
    public void sayHi(){
        System.out.println("Hello Component注解!");
    }
}

5大类注解联系

我们联系实际生活中的车牌号,我们虽然车牌号的功能都是一样,但是不同地区都有自己的车牌号!我们通过车牌号就可以分辨出这车来自哪里!
 而这里5大类注解作用也是如此,我们通过类注解,可以知道当前类的用途!
 例如;
程序的工程分层,调用流程如下:
 
 我们拿去银行办业务做类比:
类注解之前联系:
 
 可以看到其他4个注解都是Component注解的子类!
Spring给Bean命名规则
我们查看Spring源码验证!

 我们顺藤摸瓜下方就是Spring对Bean对象进行命名的方法!
 public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                        Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }
可以看到我们这里bean对象的id命名规则如下:
- 对象类类名一般采用大驼峰的形式也就是单词第一个字母大小,所以Spring直接bean对象改为小驼峰,`第一个字母分成小写!
- 对象类类名不规范,不是大驼峰,第二个字母和第一个字母都是大小!Spring直接将bean对象命名为类名!
我们进行验证:
 
方法注解@Bean
方法注解进行对象注册
//User类
public class User {
    private String name;
    private int id;
    public User(String name, int id) {
        this.name = name;
        this.id = id;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}
//Users类
@Component
public class Users {
    @Bean
    public User user(){
        return new User("java",666);
    }
}

 可以看到@Bean注解适用于返回值返回对象的方法中!
重命名Bean
我们可以通过@Bean方法注解给bean对象重命名,可以直接设置名字!
@Component
public class Users {
    @Bean(name = {"user1"})
    public User user(){
        return new User("java",666);
    }
}
能否通过之前Spring给我们设置的名字访问? 不能
 
 @Bean(name={"user1","user2"}) 重命名多个!
 
 我们也可以将name省略
 @Bean({"user1"})
 

获取Bean对象(对象装配)
实现对象装配的3种方法
- 属性注入
- 构造方法注入
- Setter注入
下面我们来演示一下这3种注入方式
我们按照实际开发将Service层的类注入到Controller层的类中!
属性注入
我们通过@Autowired实现属性注入
 service层类代码
@Service
public class UserService {
    public User getUser(){
        return new User("Mysql",666);
    }
}
controller层类代码
 通过属性注入将service层代码注入到这
@Controller
public class UserController {
    //属性注入
    @Autowired
    private UserService userService;
    public User getUser(){
        return userService.getUser();
    }
}
运行结果:
 
构造方法注入
我们还是通过@Autowired注解注入
@Controller
public class UserController {
    private UserService userService;
    //构造方法注入
    @Autowired
    public UserController(UserService userService){
        this.userService = userService;
    }
    public User getUser(){
        return userService.getUser();
    }
}

Setter注入
@Controller
public class UserController {
    //Setter注入
    private UserService userService;
    @Autowired
    public void setUserService(UserService userService){
        this.userService = userService;
    }
    public User getUser(){
        return userService.getUser();
    }
}

三种注入方式对比
- 属性注入简洁,使用方便! 缺点只能适用于IoC容器,在非IoC容器不适用,并且属性注入只有在是使用的时候才会出现空指针异常(NPE)
- 构造方法注入现在官方推荐注入方式! 缺点 如果注入多个对象,就会使得代码臃肿,不过这就是程序员的问题了,不符合程序设计的单一职责的设计模式,优点通用性强,在使用前一定可以保证注入的类不为空!
- Setter方式是Spring前期推荐的注入方式,通用性不如构造方法注入,现在已经认准构造方法注入!
@Resource注入关键字
在进行类注入时,我们还可以通过@Resource注解进行注入!
 我们只需要将@Autowired注解换成@Resource即可!
 
@Autowired和@Resource区别
- 出身不同: @Autowired注解是Spring提供的,@Resource是来自JDK下的注解
- 使用设置的参数不同:相比@Autowired注解,@Resource注解 支持更多的参数设置 例如name设置,根据name获取对象
注入同一类型多个Bean对象
我们在Users类中注册了2个相同类型的Bean对象!
@Component
public class Users {
    @Bean(name = "user1")
    public User user1(){
        User user =  new User("java",666);
        return user;
    }
    @Bean(name = "user2")
    public User user2(){
        User user = new User("MySQL",666);
        return user;
    }
}
当我们直接注入到Controller类中!
@Controller
public class UserController {
    @Resource
    private User user;
    public User getUser(){
        return user;
    }
}

 因为我们在Spring中注册了2个相同类型的User对象,所以进行对象装配时,也需要通过name属性进行声明你要装配的对象名!
@Controller
public class UserController {
    @Resource(name = "user2")
    private User user;
    public User getUser(){
        return user;
    }
}

 注意:
@Controller
public class UserController {
//    @Resource(name = "user2")
    @Autowired
    @Qualifier(value = "user1")
    private User user;
    public User getUser(){
        return user;
    }
}











