Spring更简单的读取和存储对象

存储Bean对象

之前的配置文件中spring-config.xml中,需要添加才能够把对象存入容器中。而现在只需要在存入容器的类上添加注解即可,提高了开发效率,在这之前需要在配置文件中配置上存储对象的扫描路径,只有被配置的包下的所有类,添加了注解才能被正确识别并保存到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">
	<content:component-scan base-package="com"></content:component-scan>
</beans>

image.png
如果不想配置路径,想让Spring从根路径开始搜索,填写 ** ,但是实际开发中不会这样写

使用注解存储Bean对象

类注解:@Controller @Service @Repository @Component @Configuration
@Controller //表示要把对象存入Spring中
	public class UserController {
		public void sayHi(String name) {
			System.out.println("hi: " + name);
		}
	}
public class App {
	public static void main(String[] args) {
		//1.得到Spring对象
		ApplicationContext context =
			new ClassPathXmlApplicationContext("spring-config.xml");
		//2.通过Spring取Bean对象
		UserController user = context.getBean("userController", UserController.class);
		//3. 使用Bean对象
		user.sayHi("张三");
	}
}

从Spring中获取Bean对象,Bean对象的命名规则

当使用5大类注解时,默认情况下获取Bean对象,只需要将类名首字母小写即可;当Bean对象的首字母和第二个字母都是大写时,此时需要使用原类名才能获取到Bean对象
image.png

public static void main(String[] args) {
	ApplicationContext context =
		new ClassPathXmlApplicationContext("spring-config.xml");
	UService user = context.getBean("UService", UService.class);
	user.sayHi("李四");
}
@Service
	public class UService {
		public void sayHi(String name) {
			System.out.println("hi: " + name);
		}
	}

image.png
其他类注解,这里就不一一演示了,在Spring中他们的功能都是把对象存入容器中

既然功能都类似,为什么要搞5个注解,一个类注解不就够了吗

这就类似于各个省份的车牌号,之所以不做成全国统一,就是为了方便的识别出一辆车的归属地。而这里搞多个类注解就是为了程序员能快速了解当前类的用途
@Controller(控制器): 归属于业务逻辑层,用来控制用户的行为,用来检查用户参数的有效性合理性。类似于车站的安检
@Service(服务):归属于服务层,用来调用持久化类实现相应的功能。类似于车站的咨询台,可以把乘客分配到各个检票口
@Repository(仓库):归属于持久层,直接和数据库进行交互,通常一个表对应一个@Repository。类似于各个动车执行各自的任务,有的开往北京,有的开去上海。
@Configuration(配置): 归属于配置层,用来配置当前项目的一些信息
@Component(组件): 归属于公共工具类,提供某些公共服务
image.png
:::info
五大类注解的关系
:::
点开各个注解的源码后发现,@Component是其他四个类注解的父类

方法注解@Bean

作用:通过@Bean注解把方法返回的对象存入Spring中

class User{
	private int id;
	private String name;

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

	public void setId(int id) {
		this.id = id;
	}

	public void setName(String name) {
		this.name = name;
	}
}
@Component
	public class UserComponent {
		@Bean
		public User getUser() {
			//伪代码,在spring中是不使用new的
			User user = new User();
			user.setId(1);
			user.setName("王五");
			return user;
		}

	}

注意:@Bean注解要配合类注解一起使用,因为一个项目中方法非常多,如果直接查找所有方法性能太低,所以配合类注解一起使用

public class App {
	public static void main(String[] args) {
		ApplicationContext context =
			new ClassPathXmlApplicationContext("spring-config.xml");
		//通过方法的原名取Bean对象
		User user = context.getBean("getUser", User.class);
		System.out.println(user.toString());
	}
}

:::danger
给Bean取别名
:::

class User{
	private int id;
	private String name;

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

	public void setId(int id) {
		this.id = id;
	}

	public void setName(String name) {
		this.name = name;
	}
}
@Component
	public class UserComponent {
		//取别名后,原来的方法名不能在使用
		@Bean(name = {"user1", "user2"})
		public User getUser() {
			//伪代码,在spring中是不使用new的
			User user = new User();
			user.setId(1);
			user.setName("王五");
			return user;
		}
	}
public class App {
	public static void main(String[] args) {
		ApplicationContext context =
			new ClassPathXmlApplicationContext("spring-config.xml");
		//通过方法的原名取Bean对象
		User user = context.getBean("user2", User.class);
		System.out.println(user.toString());
	}
}

**注意:**取完别名后不能再使用方法名来获取Bean对象了,没起别名时就类似刚提车没帮牌子交警不会抓你,当你办了牌照(起了别名)就不能拆掉牌照上路。

取Bean对象

在上面的代码中我们要先获取Spring上下文对象,再通过getBean()方法获取Bean对象,步骤过于繁琐,因此Spring官方又引入了“对象注入”。
对象注入有三种实现方式,如下

  1. 属性注入
  2. Setter注入
  3. 构造方法注入
属性注入
@Service
public class UserService {
    public User getUser(Integer id, String name) {
        //伪代码
        User user = new User();
        user.setId(id);
        user.setName(name);
        return user;
    }
}
@Controller
public class UserController {
    //属性注入
    @Autowired //相当于userService = new UserService()
    private UserService userService;
    public User getUser(Integer id, String name) {
        return userService.getUser(id, name);
    }
}

@Autowired的作用:相当于new UserService(),从Spring中取出UserService对象赋值

public class App {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
        UserController controller = context.getBean("userController", UserController.class);
        System.out.println(controller.getUser(1, "张三"));
    }
}

优点:

实现简单

缺点:

  1. 不如注入不可变对象(final),因为jdk规定final修饰的变量要么直接赋值,要么通过构造方法赋值

image.png

  1. 只适用于ioc容器
  2. 更容易违背单一设计原则(一个类干一件事,可能注入不相关的对象)

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

		public User getUser(Integer id, String name) {
			return userService.getUser(id, name);
		}
	}

优点:

相比于属性注入而言,更加符合单一设计原则,毕竟你多写了一个set方法

缺点:

  1. 不能注入不可变对象

image.png

  1. 注入对象可被修改,因为set是普通方法,可以在其他地方被调用,存在修改的风险

构造方法注入(Spring官方推荐)
@Controller
public class UserController {
    //构造方法注入
    private UserService userService;
    @Autowired //如果只有一个构造方法可以省略
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public User getUser(Integer id, String name) {
        return userService.getUser(id, name);
    }
}

在只有一个构造方法时@Autowired可以被省略,多个构造方法时不能被省略
优点:

  1. 可以注入一个不可变对象

image.png

  1. 注入的对象不能被修改
    1. 注入的对象可能被final修饰
    2. 构造方法是随着类的加载只执行一次,不像set方法可以被到处调用修改
  2. 注入的对象会被完全初始化(构造方法的特点)
  3. 通用性更好,不止ioc容器能用

缺点:

没有属性注入实现简单

然而在日常开发中,使用属性注入的更普遍。

@Resource注解

这是由jdk提供的”对象注入“的方式

@Controller
public class UserController {
	@Resource //jdk提供的注入关键字
	private UserService userService;
	public User getUser(Integer id, String name) {
		return userService.getUser(id, name);
	}
}

:::danger
@Autowired和@Resource的区别
:::

  1. 出生不同:@Autowired 来着Spring,而@Resource 来着JDK
  2. 顺序不同:@Autowired是先根据名称获取Bean对象,如果获取不到在根据类型来获取;而@Resource是先根据类型获取Bean对象,在根据名称来获取Bean对象
  3. 功能不同:@Autowired支持属性注入,setter注入,构造方法注入;而@Resource支持属性注入,setter注入,不支持构造方法注入
  4. 参数支持不同:@Resource支持更多的参数设置;而@Autowired不支持

解决同一类型多个Bean的报错

@Service
public class UserService {
    @Bean
    public User getUser1() {
        //伪代码
        User user = new User();
        user.setId(1);
        user.setName("张三");
        return user;
    }
    @Bean
    public User getUser2() {
        //伪代码
        User user = new User();
        user.setId(2);
        user.setName("李四");
        return user;
    }
}
@Controller
public class UserController {
    @Resource
    private User user;

    public User getUser() {
        return user;
    }

}

image.png
获取到两个Bean对象,发生了冲突
处理方法

  1. 使用@Resource(name=“”)

image.png
指定获取getUser1这个方法返回的User对象

  1. 使用@Qualifier

image.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

指挥部在下面

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值