Spring更简单读取和存储对象

目录

前言

注解

存储Bean

通过类注解

配置扫描路径

添加类注解存储Bean对象

@Controller(控制器存储)

@Service(服务存储)

 @Repository(仓库存储)

 @Component(组件存储)

 @Configuration(配置存储)

 类注解之间的关系

Bean的命名规则

通过方法注解

重命名Bean

方式一

方式二

方式三

方式四

获取Bean(对象装配)

属性注入

属性注入的优缺点

Setter注入

Setter注入优缺点

构造方法注入

构造方法优点


前言

上篇文章介绍了spring的创建和基本的存储、读取对象的方式,但是在操作过程中我们发现过程其实是很麻烦的,所以接下来我们将学习更加简单的读取和存储对象的方式。

注解

在Spring框架中,注解是一种用于配置和管理应用程序组件的特殊标记,通过使用注解,可以简化配置和开发过程,使整体代码更加的清晰,易读和易于维护。

在Spring中想要更加简单的存储和使用对象的核心就是使用注解。

存储Bean

通过类注解

其实当我们在学习JavaEE这块的时候,我们的思想首先应该转变一下,回忆之前的代码,很多时候我们都是自己写功能,自己写实现方式,其实在spring部分,我们想要实现一个功能,我们首先应该想到有没有对应实现该功能的注解。

我们在之前进行Bean的存储时,需要在spring-config.xml这个文件中添加一个bean标签用于注册Bean才行。

这是之前我们的写法,如果有多个Bean对象需要存储时,此时就很麻烦了,就需要一个Bean写一个bean标签了,而现在我们只需要一个注解就可以解决之前的尴尬了。

配置扫描路径

想要将对象存储到spring容器中去,我们就需要配置一下存储对象的扫描包路径,只有在我们配置了扫描包路径下面的类,添加了注解之后,才会正确的存储到spring容器中去。

和之前创建spring的方式一致,我们需要有spring-config.xml这个配置文件。

在spring-config.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: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.java.domo">

    </content:component-scan>
</beans>

也就是说,只有在这个路径下,同时使用了注解才能被spring存储。

添加类注解存储Bean对象

想要将对象存储到Spring中,有两种注解可以实现:

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

@Controller(控制器存储)

使用@Controller注解存储Bean对象:

@Controller
public class UserController {
    public void sayHi() {
        System.out.println("hello Controller");
    }
}

然后我们在通过之前获取对象的方式来读取上面的UserController对象。

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        UserController userController = context.getBean("userController", UserController.class);
        userController.sayHi();
    }
}

可以看到对象是成功的获取到了,并且成功的调用了里面的方法。

@Service(服务存储)

使用@Service注解存储Bean对象:

@Service
public class UserService {
    public void sayHi(String name) {
        System.out.println("name=" + name);
    }
}

读取Bean:


public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.sayHi("hello");
    }
}

 @Repository(仓库存储)

使用@Repository注解存储Bean对象:

@Repository
public class UserRepository {
    public void sayHi(String name) {
        System.out.println("name="+ name);
    }

}

获取Bean:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        UserRepository userRepository = context.getBean("userRepository", UserRepository.class);
        userRepository.sayHi("Repository");
    }
}

 @Component(组件存储)

使用@Component注解存储Bean对象:

@Component
public class User01 {
    public void sayHi(String name) {
        System.out.println("name="+name);
    }
}

获取Bean:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        User01 user01 = context.getBean("user01", User01.class);
        user01.sayHi("Component");
    }
}

 @Configuration(配置存储)

使用@Configuration存储Bean对象:

@Configuration
public class UserConfiguration {
    public void sayHi(String name) {
        System.out.println("name="+name);
    }
}

获取Bean:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        UserConfiguration userConfiguration = context.getBean("userConfiguration", UserConfiguration.class);
        userConfiguration.sayHi("Component");
    }
}

 类注解之间的关系

从上述的代码可以看出来的是,上述的5大类注解的功能是一样。

既然功能是一样,但是还是有5个,不是一个,这是因为当程序员看到了当前类注解之后,就能快速的明白当前类的主要用途。

比如:

@Controller 使用了这个注解的类表示的是业务逻辑层

@Service  使用这个类注解的类表示的服务层

@Repository 使用了这个类注解的类表示数据持久层

@Component  使用了这个类注解的类表示工具类层

@Configuration  使用了这个类注解的类表示配置层

这里我们需要知道程序整体之间的调用逻辑:

 

 5个类注解之间关系则是继承关系:

可以看到 @Controller、@Service、@Repository、@Configuration则是全部继承与@Component。

Bean的命名规则

上述代码我们可以看出,通常我们Bean使用的都是大驼峰命名,而读取的时候则是首字符小写的方式读取。如下图:

 如果我们把获取Bean时的名称不按照上述名称的方式进行读取时,就会出现错误。

我们接下来就可以看看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也是按照首字符大写的方式存储了,第二个字符也是大写。

如果不是第一个和第二个都是大写的情况下,就是安装首字符小写的方式进行存储了。

通过方法注解

类注解是添加到某个类上的,而方式注解则是添加到某个方法上的。

需要注意的是,这些类都是在我们前面在spring-config.xml配置文件中配置的扫描包路径下的。

User类:

public class User {
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Users类:在Users类中通过方法注解获取User对象。 

@Component
public class Users {
    @Bean
    public User user1() {
        User user = new User();
        user.setName("张三");
        return user;
    }
}

将User对象返回并打印信息:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        User user = context.getBean("user1", User.class);
        System.out.println(user.toString());
    }
}

 上述代码我们可以看出,方法注解是配合类注解一起使用的。如果没有配合类注解的话,是不能正确的存储和获取bean对象的。

从上述代码我们可以看到,在获取Bean时的命名是和方法名一致的。也就是说在获取bean时的默认命名则是方法名。

重命名Bean

方式一

可以通过@Bean注解中直接赋值的方式给对象进行重命名的操作:

@Component
public class Users {
    @Bean("u1")
    public User user1() {
        User user = new User();
        user.setName("张三");
        return user;
    }
}

此时我们就可以使用u1来获取User对象了:

public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        User user = context.getBean("u1", User.class);
        System.out.println(user.toString());
    }
}
方式二

可以通过@Bean注解中的name属性给Bean对象进行重命名操作:

@Component
public class Users {
    @Bean("u2")
    public User user1() {
        User user = new User();
        user.setName("张三");
        return user;
    }
}
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        User user = context.getBean("u2", User.class);
        System.out.println(user.toString());
    }
}
方式三

通过@Bean注解中的value属性给Bean对象进行重命名操作:

@Component
public class Users {
    @Bean(value = "u3")
    public User user1() {
        User user = new User();
        user.setName("张三");
        return user;
    }
}
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        User user = context.getBean("u3", User.class);
        System.out.println(user.toString());
    }
}
方式四

通过重命名扩展的方式给Bean设置名称:

@Component
public class Users {
    @Bean(value={"u4","u5","u6"})
    public User user1() {
        User user = new User();
        user.setName("张三");
        return user;
    }
}

通过上述的这种方式设置名称后,就可以通过任意一个名称进行Bean对象的获取了。

注意:在@Bean重命名后,那么默认的根据方法名获取Bean对象的方式就不能使用了。

 

获取Bean(对象装配)

获取Bean对象也叫对象装配,是把某个对象取出来放在某个类中,也称为对象注入。

对象装配(对象注入)的方式有3种:

  • 属性输入
  • Setter注入
  • 构造方法注入

属性注入

属性注入是通过@Autowired注解实现的。

下面我们按照实际开发的方式进行注入:

 整个项目结构。

我们在UserRepository里面假设将获取数据库中的数据,并封装了一个方法进行查询数据库操作。然后将查询到的数据库放入User对象中,进行返回。

然后在UserService里面通过属性注入的方式注入,再调用UserRepository里面的获取数据库的方法。

然后在UserController里面将UserService通过属性注入的方式注入,再调用UserService里面的方法。

整体流程是UserController——>UserService——>UserRepository(进行数据库查询,返回对象)。

UserRepository类具体实现:


@Repository
public class UserRepository {

    public User getUser() {
        //伪代码   具体业务的实现
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
}

UserService类具体实现:


@Service
public class UserService {

    @Autowired   //通过注解的方式将对象注入到这里
    private UserRepository userRepository;
 
    public User getUser() {    //在通过注入的对象进行业务的实现
        return userRepository.getUser();
    }
}

UserController类具体实现:

@Controller
public class UserController {

    @Autowired   //通过属性注入的方式将UserService注入
    private UserService userService;

    public User getUser() {  //在通过注入的对象进行业务的实现
        return userService.getUser();
    }
}

可以看到比之前下面这种获取对象的方式更加方便了。

// Spring V1.0      依赖查找
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-config.xml");
        UserRepository userRepository = context.getBean("userRepository",UserRepository.class);
        return userRepository.getUser();

 

执行代码能成功的获取到从数据库返回的对象。

属性注入也称为依赖注入,我们之前用到的获取Bean对象的方式是属于依赖查找。

依赖注入VS依赖查找:

依赖查找时根据Bean名称的

依赖注入则是先根据类型从容器中获取对象,如果只能获取一个,那么就直接将此对象注入到当前属性上,如果获取到多个对象,才会使用名称进行匹配。

属性注入的优缺点

优点:使用简单

缺点:

  • 无法注入通过final修饰的变量
  • 只适用于IoC容器
  • 更容易违背单一设计原则,因为使用起来简单,更容易注入其他类型的对象

Setter注入

Setter注入和属性Set方法实现类似,只不过在设置Set方法时需要添加上@Autowired注解。

@Controller
public class UserController {

    //Setter注入
    private UserService userService;

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


    /*@Autowired  属性注入
    private UserService userService;*/

    public User getUser() {
        return userService.getUser();
    }
}
Setter注入优缺点

优点:完全符合单一设计原则,因为setter注入每次都只能设置一个对象。

缺点:

  • 不能注入final修饰的不可变对象
  • 注入的对象可以被随时修改

因为final修饰的属性只能在定义的时候进行初始化,或者在构造方法中进行初始化。

注入的对象可以被修改是因为提供了setXXX方法,意味着我随时可以调用这个方法来改变注入对象。

构造方法注入

构造方法注入是在类的构造方法中进行注入:


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

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


    /*@Autowired  属性注入
    private UserService userService;*/
    public User getUser() {
        return userService.getUser();
    }
}

注意:如果一个类中只有一个构造方法,那么不加@Autowired注解也是可以的,但是如果多个构造方法,就需要加上注解,用来表示到底使用那个构造方法进行注入。

构造方法优点
  • 可以注入不可变对象,也就是final修饰的对象,因为final修饰的属性只能在初始化或者构造方法中赋值。
  • 注入的对象不会被修改,因为构造方法只执行一次。
  • 注入的对象会完成被初始化,因为在对象创建之前,被注入的对象会被完成的初始化,在进行注入。
  • 通用性更好,可以适用于非IoC的框架。
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值