Sping对象的存储和读取


一、更简单的存储对象到Sping的实现步骤

1.先创建一个Maven

在这里插入图片描述

2. 添加Spring Maven核心包

pom.xml中添加Spring的上下文和管理对象模块

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
</dependencies>

3.配置Spring xml 文件 ->配置Spring组件扫描路径(所有需要存储在Spring中的对象都需要放在此目录)

在resource目录下新建一个xml文件,并配置Spring组件的扫描路径

在这里插入图片描述
也就是说,只有在com.demo下的类才有可能被存储到Spring当中

<?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">

    <!-- 配置 Spring 扫描根路径 (此根路径下所有 Spring 存对象的注解才能生效 ) -->
    <!-- 值有根路径下的类才有可能被存到Spring中 -->
    <content:component-scan base-package="com.demo"></content:component-scan>
</beans>

4. 创建一个普通类,添加Main(作用:方便后面演示)

5. 使用注解实现对象存储在Spring框架(类注解/方法注解)

1.类注解:@Controller[控制器]、@Service[业务逻辑类]、@Repository[数据持久类]、@Component[组件类]、@Configuration[配置类]
2.方法注解:@Bean

在这里插入图片描述

@Controller 控制器 (对象存储)

@Controller // 将当前的类存储到 Spring 中
public class UserController {
    
    
    /**
     * 对象中的测试方法
     * @param name
     */
    public void testHello(String name) {
    
    
        System.out.println("hello Controller " + name);
    }
}

注意事项:

  1. 读取存入对象的id:默认情况下就是首字母小写

在这里插入图片描述

  1. 所有需要存储到 Spring框架中的对象的目录,必须在Spring 配置的目录下,conmponent-scan

在这里插入图片描述

@Service 业务逻辑类

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

@Repository[数据持久层](DAO)

@Repository // 将对象存储到 Spring中
public class UserRepository {
    
    
    public void printRepository(String name) {
    
    
        System.out.println("hello repository "+name);
    }
}

@Component[组件类]

@Component //将对象存储到Spring中
public class UserComponent {
    
    
    public void printComponent(String name) {
    
    
        System.out.println("hello component "+name);
    }
}

@Configuration[配置类]

@Configuration // 将对象存储到Spring中
public class UserConfiguration {
    
    
    public void printConfiguration(String name) {
    
    
        System.out.println("hello Configuration "+name);
    }
}

@Bean

@Bean方法注解,可以把方法返回的对象注入到Spring中

public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");

        //  得到 controller 对象
        UserController controller = applicationContext.getBean("userController",UserController.class);
        controller.printController("控制器");

        // 得到 service 对象
        UserService service = applicationContext.getBean("userService",UserService.class);
        service.printService("业务逻辑");

        // 得到 repository对象
        UserRepository repository = applicationContext.getBean("userRepository",UserRepository.class);
        repository.printRepository("数据持久DAO");

        // 得到 configuration
        UserConfiguration configuration = applicationContext.getBean("userConfiguration",UserConfiguration.class);
        configuration.printConfiguration("配置类");

        // 得到 component
        UserComponent component = applicationContext.getBean("userComponent",UserComponent.class);
        component.printComponent("组件类");
    }

6.使用方法注解 @Bean 将对象存储到 Spring

注意事项:Spring 默认情况下是类扫描,因此如果使用的是方法注解 @Bean,那么必须要配合类注解(@Component)一起使用(也可以是其它注解),才能将方法返回对象顺利存储到 Spring中

@Component
public class UserBean {
    
    
    @Bean
    public User user() {
    
    
        //伪代码
        //查询数据库获取对象

        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(20);

        return user;
    }
}

获取对象

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //通过 @Bean注解获取对象
        User user = applicationContext.getBean("user",User.class);
        System.out.println(user);
    }
}

7.@Bean起别名

注意:如果给@Bean起别名后,就只能用别名来获取对象了

@Component
public class UserBean {
    
    
    @Bean(name = {
    
    "getUser"})
    public User user() {
    
    
        //伪代码
        //查询数据库获取对象

        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(20);

        return user;
    }
}

获取对象

public class App {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //通过 @Bean注解获取对象
        User user = applicationContext.getBean("getUser",User.class);
        System.out.println(user);
    }
}

@Bean还可以起多个别名

@Component
public class UserBean {
    
    
    @Bean(name = {
    
    "getUser","myUser"})
    public User user() {
    
    
        //伪代码
        //查询数据库获取对象

        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(20);

        return user;
    }

}

并且 nume = 可以省略

@Bean({
    
    "getUser","myUser"})
    public User user() {
    
    
        //伪代码
        //查询数据库获取对象

        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(20);

        return user;
    }

8.注解之间的关系

为啥要有那么多注解,就是让程序员看到类注解之后,就能直接了解当前类的⽤途

通过源码可以发现,@controller/@Service/@Repository/@Configuration
这四个注解从业务逻辑来说,可以认为这四个注解是 @Component的子类

在这里插入图片描述

9.Spring是如何生成出类注解 beanName的?

查看 AnnotationBeanNameGenerator 中的源码
AnnotationBeanNameGenerator -> buildDefaultBeanName -> Introspector.decapitalize(shortClassName)

如果类名的长度大于1,并且第一个和第二个字母都是大写就直接返回
否则就把类名的第一个字母改为小写直接返回

在这里插入图片描述

二、更简单的从Spring获取对象(@Autowired )

从Spring中获取对象的手段:

  1. 属性注入(属性注册)UserController ——> UserService
  2. Setter 注入
  3. 构造方法注入
@Service //将当前对象存储到 Spring 当中
public class UserService {
    
    
    /**
     * 通过用户Id查询用户
     * @param id
     * @return
     */
    public User findUserById(int id) {
    
    
        // 伪查询,不连接sql
        User user = new User();
        if (id == 1) {
    
    
            user.setId(1);
            user.setName("张三");
            user.setAge(18);
        } else {
    
    
            user.setId(2);
            user.setName("李四");
            user.setAge(20);
        }

        return user;
    }
}

1. 属性注入

属性注⼊是使⽤ @Autowired 实现的,将 UserService 类注⼊到 Controller 类中

@Controller // 将当前的类存储到 Spring 中
public class UserController {
    
    
    // 属性注入(属性注册), 从Spring中取出对象,注入到当前类中
    @Autowired
    private UserService userService;

    public User findUserById(Integer id) {
    
    
        if (id == null) {
    
    
            // 如果是无效参数
            return new User();
        }
        return userService.findUserById(id);
    }
}

2. Setter注入

注意:必须在 Setter方法上加上 @Autowired 注解,不然会注入失败。又因为spring是类扫描的,所以要在当前类上加上对应注解,该对象才有可能存入 spring 中

@Controller
public class UserController2 {
    
    
    private UserService userService;

    public User findUserById(Integer id) {
    
    
        if (id == null) {
    
    
            return new User();
        }

        return userService.findUserById(id);
    }

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

3. 构造方法注入

注意:如果类中只有一个构造方法,@Autowired注解可以省略

@Controller
public class UserController3 {
    
    
    private UserService userService;

    //通过构造方法注入,若果只是存在一个构造方法,那么@Autowired可以省略
    @Autowired
    public UserController3(UserService userService) {
    
    
        this.userService = userService;
    }

    public UserController3(String name) {
    
    
        System.out.println(name);
    }

    public User findUserById(Integer id) {
    
    
        if (id == null) {
    
    
            //判断id合法
            return new User();
        }

        return userService.findUserById(id);
    }
}

三种方式的getBean实现

public static void main(String[] args) {
    
    
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        // 方法1: 属性注入
        UserController userController = (UserController) context.getBean("userController");
        System.out.println(userController.findUserById(2));

        // 方法2: Setter注入
        UserController2 userController2 = context.getBean("userController2",UserController2.class);
        System.out.println(userController2.findUserById(1));

        // 方法3: 构造方法注入
        UserController3 userController3 = context.getBean("userController3",UserController3.class);
        System.out.println(userController3.findUserById(2));
    }

三种注入方式的区别

  • 属性注入的优点,使用方便;缺点是只能用于 Ioc容器,如果不是IoC容器就无法使用,并且只有在使用的时候才会出现 空指针异常
  • 构造方法注入是 Spring官方推荐的注入方式,它的缺点是如果有多个注入会显得比较臃肿,但出现这种情况你应该考虑一下当前类是否符合程序的单一职责的设计模式了,它的优点是通用性,在使用之前一定能保证注入的类不为空
  • Setter方式是Spring前期版本推荐的注入方式,但通用性不如构造方法,所以Spring先版本已经推荐使用构造方法注入的范式来进行类注入了

另外一种从Spring获取对象注解(@Resource )

@Resource 和 @Autowired 注解的使用方式非常类似

1.属性注入

@Controller
public class UserController4 {
    
    
    @Resource
    private UserService userService;

    public User findUserById(Integer id) {
    
    
        if (id == null) {
    
    
            return new User();
        }

        return userService.findUserById(id);
    }
}

2. Setter注入

@Controller
public class UserController5 {
    
    
    private UserService userService;

    public User findUserById(Integer id) {
    
    
        if (id == null) {
    
    
            return new User();
        }
        return userService.findUserById(id);
    }

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

注意:@Resource不能通过构造方法注入对象

在这里插入图片描述

@Autowired 和 @Resource 关于注入对象名称的问题

@Autowired 和 @Resource 它们都是做了两手准备,它们会先从 一种类型进行选择,比如先从名称(ByName)进行获取Bean对象,如果根据名称获取不到,此时根据另一种类型(ByType)获取(根据名称或者类型获取

如果Bean对象只有一个的时候,注入对象名就无所谓了

在这里插入图片描述

问题来了:如果注入的名称是不存在的,并且类型有多个,那么注入就会失败

@Component
public class UserBean {
    
    

    @Bean
    public User getUser1() {
    
    
        User user = new User();
        user.setId(1);
        user.setName("张三");
        user.setAge(22);

        return user;
    }

    @Bean
    public User getUser2() {
    
    
        User user = new User();
        user.setId(2);
        user.setName("李四");
        user.setAge(20);

        return user;
    }
}

注入代码

@Service
public class UserService {
    
    

    @Resource
    private User user;

    public User findUserById(int id) {
    
    
        User user = new User();
        if (id == 1) {
    
    
            user.setId(1);
            user.setName("张三");
            user.setAge(18);
        } else {
    
    
            user.setId(2);
            user.setName("李四");
            user.setAge(20);
        }

        return user;
    }
}

运行就会报错,因为这里名字不存在,并且有多个类型注入

同⼀类型多个 Bean 报错处理,可以为Bean重命名,再通过重命名的名字注入Bean对象

  1. 使用 @Resource(name=“指定bean名称”)
    加上 name 说明加载的时候是用 beanName加载的
@Service
public class UserService {
    
    

    @Resource(name = "getUser1")
    private User user;

    public User findUserById(int id) {
    
    
        User user = new User();
        if (id == 1) {
    
    
            user.setId(1);
            user.setName("张三");
            user.setAge(18);
        } else {
    
    
            user.setId(2);
            user.setName("李四");
            user.setAge(20);
        }

        return user;
    }
}

在这里插入图片描述
2.使用注入注解配合@Qualifier来进行解决

@Service
public class UserService {
    
    

    @Autowired
    @Qualifier(value = "getUser2")
    private User user;

    public User findUserById(int id) {
    
    
        User user = new User();
        if (id == 1) {
    
    
            user.setId(1);
            user.setName("张三");
            user.setAge(18);
        } else {
    
    
            user.setId(2);
            user.setName("李四");
            user.setAge(20);
        }

        return user;
    }
}

在这里插入图片描述

@Autowired 和 @Resource 有什么区别?

  1. 出身不同,@Autowired 来自于 Spring 框架,而 @Resource来自于 JDK
  2. 作用于不同,使用@Autowired可以进行 属性注入、Setter注入、构造器注入;而 @Resource只能进行 属性注入和Setter注入。
  3. 功能不同,@Resource可以配合更多属性进行使用,而 @Autowired 支持的属性较少,比如 @Resource 可以 配合 name 属性进行使用,从而完成对象的别名注入

猜你喜欢

转载自blog.csdn.net/weixin_53946852/article/details/129555152