【Spring】万字详解使用注解来存取对象

使用注解来存取对象

    • 一、配置扫描路径
    • 二、添加注解存储Bean对象
      • 2.1类注解
        • 2.1.1 @Controller存储
        • 2.1.2 @Service存储
        • 2.1.3 @Repository存储
        • 2.1.4 @Component存储
        • 2.1.5 @Configuration存储
        • 2.1.6 为什么有这么多类注解?
      • 2.2 Bean的命名规则
      • 2.3 方法注解@Bean
        • 2.3.1 重命名Bean
    • 三、获取Bean对象
      • 3.1 属性注入
      • 3.2 构造方法注入
      • 3.3 Setter注入
      • 3.4 三种注入方式的优缺点
      • 3.5 @Resource:另一种注入关键字
        • 3.5.1 经典面试题: @Resource和@Autowired的区别
      • 3.6 同一个类型下多个Bean报错

上篇文章中我们详细的讲解了Spring对象的存取和使用,感兴趣的朋友可以去看上篇文章Spring的创建和使用,但是上篇文章中讲的存取对象的方法相对来说有些繁琐,这篇文章我们就介绍使用注解的方式来进行存储对象吧~~

一、配置扫描路径

这里说的配置扫描路径的方式就是在spring的配置文件中配置一下存储对象的包的路径,只有被配置的包下的所有类,添加了注解才能被识别并注册到Spring中。
试想一下,如果不配置路径,那么较大的项目中有成百上千个类,那么就要一个一个类挨着扫描,性能很低。

在配置文件中添加:


<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">
    
    <content:component-scan base-package="com.beans">content:component-scan>
beans>

【Spring】万字详解使用注解来存取对象_第1张图片

二、添加注解存储Bean对象

配置好扫描路径后,就可以通过添加注解将对象存储在Spring中,有以下两种注解类型:

  • 类注解:@Controller、@Service、@Repository、@Component、@Configuration
  • 方法注解:@Bean

注意事项:

  • 即使在配置文件中配置了bean扫描路径,但是五大类注解是不能省略的。
  • 即使添加了五大类注解,但是类没有放在spring配置的根路径下,那么类也不能注入到spring中。

2.1类注解

2.1.1 @Controller存储

使用@Controller存储bean:

@Controller
public class UserController {
    public void sayHi(String name){
        System.out.println("Hi "+name);
    }
}

使用之前的方式获取UserController对象:

/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        //2.得到bean
        UserController userController=context.getBean(UserController.class);
        //3.使用bean
        userController.sayHi("java");
        }
    }

【Spring】万字详解使用注解来存取对象_第2张图片

2.1.2 @Service存储

使用@Service存储bean:

@Service //将当前bean对象存储到spring中
public class UserService {
    public void sayHi(String name){
        System.out.println("Hi "+name);
    }
}

使用之前的方式获取UserService 对象:

/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.sayHi("javaee");
        }
    }

【Spring】万字详解使用注解来存取对象_第3张图片

2.1.3 @Repository存储

使用@Repository存储bean:

@Repository //将对象注入到spring中
public class UserRepository {
    public void sayHello(String name){
        System.out.println("Hello "+name);
    }
}

使用之前的方式获取UserRepository 对象:

/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        UserRepository userRepository = context.getBean("userRepository", UserRepository.class);
        userRepository.sayHello("世界");
        }
    }

【Spring】万字详解使用注解来存取对象_第4张图片

2.1.4 @Component存储

使用@Component存储bean:

@Component //将对象注入到spring中
public class UserComponent {
    public void sayHello(String name){
        System.out.println("Hello "+name);
    }
}

使用之前的方式获取UserComponent 对象:

/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        UserComponent userComponent = context.getBean("userComponent", UserComponent.class);
        userComponent.sayHello("world");
        }
    }

【Spring】万字详解使用注解来存取对象_第5张图片

2.1.5 @Configuration存储

使用@Configuration存储bean:

@Configuration //将对象注入到spring中
public class UserConfiguration {
    public void sayHello(String name){
        System.out.println("Hello "+name);
    }
}

使用之前的方式获取UserConfiguration 对象:

/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        UserConfiguration userConfiguration = context.getBean("userConfiguration", UserConfiguration.class);
        userConfiguration.sayHello("world");
        }
    }

【Spring】万字详解使用注解来存取对象_第6张图片

2.1.6 为什么有这么多类注解?

我们来看一下除了Component之外其他四个类注解的源码,不难发现,他们都是依靠@Component实现的,因此可以说@Component式其他四个类注解的父类。
【Spring】万字详解使用注解来存取对象_第7张图片
【Spring】万字详解使用注解来存取对象_第8张图片
【Spring】万字详解使用注解来存取对象_第9张图片
【Spring】万字详解使用注解来存取对象_第10张图片

那么这些类的功能都相同,为什么还要有这么多类注解呢?
其实就像我们国家的车牌一样,会根据省份进行划分,省份会进一步根据省内的城市进行划分,这样交警叔叔在看到车牌号后,一下就可以辨别这个车是哪个省哪个城市的车。
那么spring中的类注解也是同样的道理,就是通过这些注解来对我们的工程进行分层,每个注解代表不同的用途,那么这样当程序员一看到这个注解就知道这个类是用来做什么的。
【Spring】万字详解使用注解来存取对象_第11张图片

2.2 Bean的命名规则

1.类名使用大驼峰命名,读取的时候将首字母小写即可。
【Spring】万字详解使用注解来存取对象_第12张图片

2.类名的首字母和第二个字母都是大写,则在读取的时候使用原类名。
【Spring】万字详解使用注解来存取对象_第13张图片
这是为什么呢?
我们就要来看看bean命名规则的源码:
【Spring】万字详解使用注解来存取对象_第14张图片
它使用了JDK中的decapitalize方法:

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);
    }

这个方法很清晰的说明了命名规则,就是我们上面提到的两种。

2.3 方法注解@Bean

注意~~
方法注解必须配合五大类注解其中之一进行使用才有效,否则无效。

@Component
public class UserBeans {
    @Bean  //将当前方法返回的对象存储到spring中,默认bean是方法名
    public User getUser(){
        User user=new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123456");
        return user;
    }
}

/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        User user1=context.getBean("getUser",User.class);
        System.out.println(user1);
        }
    }

【Spring】万字详解使用注解来存取对象_第15张图片

2.3.1 重命名Bean

【Spring】万字详解使用注解来存取对象_第16张图片

@Component
public class UserBeans {
    @Bean(name="user1")  //将当前方法返回的对象存储到spring中,默认bean是方法名
    public User getUser(){
        User user=new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123456");
        return user;
    }
}
/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
        User user1=context.getBean("user1",User.class);
        System.out.println(user1);
        }
    }

【Spring】万字详解使用注解来存取对象_第17张图片
在对Bean进行重命名之后,就不可以使用原来的类名首字母小写和方法名进行获取对象。

三、获取Bean对象

存储完对象,就可以来取对象了。
获取对象又叫也叫做对象装配,是把对象取出来放到某个类中,也叫对象注入

分为以下三种注入方式:

  1. 属性注入
  2. 构造方法注入
  3. Setter注入

以下注入方式的演示,都是将Service注入到Controller类中。

3.1 属性注入

属性注入就是在属性上加上@Autowired,将Service注入到Controller类中。

Service类实现:

@Service //将当前bean对象存储到spring中
public class UserService {
    public void sayHi(String name){
        System.out.println("Hi "+name);
    }

    /**
     * 根据id获取用户
     * @param id
     * @return
     */
    public User getUserById(int id){
        //伪代码
        User user=new User();
        user.setId(id);
        user.setName("雪雪");
        user.setPassword("1234");
        return user;
    }
}

Controller类:


@Controller
public class UserController {
    //1.属性注入
    @Autowired
    private UserService userService;

    public void sayHi(String name){
        System.out.println("Hi "+name);
    }
    public User getUserId(Integer id){
        //伪代码
        return userService.getUserById(id);
    }
}

获取Controller中的getUserId的方法:

/**
 * 启动类
 */
public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml")
        UserController userController = context.getBean("userController",UserController.class);
        System.out.println(userController.getUserId(10));
    }
}

【Spring】万字详解使用注解来存取对象_第18张图片

3.2 构造方法注入

@Controller
public class UserController2 {
    private UserService userService;
    //2.构造方法注入
    @Autowired
    public UserController2(UserService userService){
        this.userService=userService;
    }


    public void sayHi(String name){
        System.out.println("Hi "+name);
    }
    public User getUserId(Integer id){
        //伪代码
        return userService.getUserById(id);
    }
}

注意:如果当前类中只有一个构造方法,那么不加@Autowied注解也是可以获取到User对象,但是如果有多个构造方法,那就必须加@Autowied注解。

3.3 Setter注入

@Controller
public class UserController3 {
    private UserService userService;

    //3.setter注入
    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void sayHi(String name){
        System.out.println("Hi "+name);
    }
    public User getUserId(Integer id){
        //伪代码
        return userService.getUserById(id);
    }
}

Setter注入必须加 @Autowired注解,如果不加,就会报NullPointerException。
【Spring】万字详解使用注解来存取对象_第19张图片

3.4 三种注入方式的优缺点

  • 属性注入:写法最简单,也最简洁。缺点是不通用,它只适用于loC框架,非loC框架不可用,只有在使用时会出现空指针异常。
  • Setter注入:Spring 早期版本推荐的注入方式,它的通用性不如构造方法注入。
  • 构造方法注入:缺点是可能存在传递多个参数来实现构造方法的初始化,会导致代码很臃肿,那么如果出现了这种情况那么开发者应该反思自己写的代码是否符合单一职责的设计模式了;优点是通用性更好,并且他能保证在调用对象之前,此对象一定是存在的。Spring后期版本官方推荐的注入方式。

3.5 @Resource:另一种注入关键字

在进行获取对象时,除了可以使用@Autowired注解外,还可以使用@Resource注解。

@Controller
public class UserController5 {
    private UserService userService;

    @Resource
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void sayHi(String name){
        System.out.println("Hi "+name);
    }
    public User getUserId(Integer id){
        //伪代码
        return userService.getUserById(id);
    }
}
3.5.1 经典面试题: @Resource和@Autowired的区别
  1. 出身不同:@Autowired来自Spring,而 @Resource来自于JDK。
  2. 使用时设置的参数不同:@Autowired只支持required参数设置,@Resource支持更多的参数设置。如name等。
  3. 支持不同:@Autowired支持属性注入、构造方法注入、Setter注入,而@Resourc只支持属性注入和Setter注入,不支持构造方法注入。

3.6 同一个类型下多个Bean报错

@Component
public class UserBeans {
    @Bean(name="user1")  //将当前方法返回的对象存储到spring中,默认bean是方法名
    public User getUser(){
        User user=new User();
        user.setId(1);
        user.setName("张三");
        user.setPassword("123456");
        return user;
    }

    @Bean(name="user2")
    public User getUser2(){
        User user=new User();
        user.setId(2);
        user.setName("李四");
        user.setPassword("456");
        return user;
    }
}

@Controller
public class UserController6 {
    @Resource
    private User user;

    public void sayHi(){
        System.out.println(user);
    }
}

【Spring】万字详解使用注解来存取对象_第20张图片

怎么解决呢?

  1. 使用@Resource(name = “user1”)定义
@Controller
public class UserController6 {
    @Resource(name="user2")
    private User user;

    public void sayHi(){
        System.out.println(user);
    }
}

【Spring】万字详解使用注解来存取对象_第21张图片

  1. 使用@Autowired+@Qualifier注解定义
@Controller
public class UserController6 {
    @Autowired
    @Qualifier(value="user1")

    private User user;

    public void sayHi(){
        System.out.println(user);
    }
}

【Spring】万字详解使用注解来存取对象_第22张图片

你可能感兴趣的:(Java,Web,spring,java)