您现在的位置是:首页 >其他 >Spring的创建与Bean对象的存取网站首页其他
Spring的创建与Bean对象的存取
文章目录:一.Spring项目的创建1.先创建maven项目
2.添加国内源
3.添加spring依赖
4.创建spring配置文件
5.创建启动类
二.Bean对象的创建和读取1.Bean对象的创建与存储方式(1)类注解
(2)方法注解
(3)<bean>格式
2.Bean对象的获取方式(1)通过id
(2)通过类名
(3)id+类名
(4)注解@Autowired
(5)@Autowired @Resource区别
一.Spring项目的创建
1.先创建一个maven项目
2.添加国内源
查看Local reposittory目录下是否有settings这个文件
将settings.xml文件里在<mirros>里面添加阿里云镜像
3.添加spring-content依赖
4.添加配置文件在resources底下
在文件里添加如下内容
<?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="kale"></content:component-scan>
<!--<bean id="beanlife" class="kale.pole.Beanlife" init-method="init" destroy-method="preDestroy"> </bean>-->
</beans>
5.添加启动类
二.Bean对象的创建与读取
1.Bean对象的创建
我们先来创立一个Student类
package spring;
public class Student {
public String name="网红";
public int id=3;
public int score=97;
String s=new String();
public Student()
{
System.out.println("学生初始化");
}
public void say()
{
System.out.println("你好学生");
}
}
在resources文件底下,新建一个spring-config(文件名可以随意起) xml文件
在xml文件里引入:
将bean对象存储到spring容器中
然后我们就可以在里面注册bean 对象,我们将student对象注册到spring中
<bean id="student" class="spring.Student"></bean>
其中 class后面需要写 包名+类名
2.从spring容器中获取bean
1.因为我们是在spring中注册bean,如果我们想要获取到,我们需要先获取到spring上下文,这里我们就涉及到两个类(ApplicationContext、BeanFactory)
2.然后根据注册的id,来获取对应的bean对象
public static void main(String[] args) {
(1)//获取spring上下文
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
(2)//根据id来取容器里对应的bean对象
Student result=(Student)context.getBean("student");
result.say();
}
3.ApplicationContext BeanFactory有什么区别:
我们再来创建一个Teacher类,然后在spring中将实例化的对象给注册到里面去
package spring;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
public class Teacher {
public Teacher()
{
System.out.println("教师初始化");
}
public void say()
{
System.out.println("你好,教师");
}
}
<bean id="teacher" class="spring.Teacher"></bean>
我们先来用 ApplicationContext 来演示
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
}
我们可以发现当用去获取上下文时,spring中所有的类都被加载了,也就是在这时我们才真正的去创建bean对象,一开始在spring-config.xml中我们只是去注册、声明bean对象。
我们再来看一下,BeanContext
public static void main(String[] args) {
BeanFactory context=new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
}
当我们去运行这个程序的时候,发现什么都没有
public static void main(String[] args) {
BeanFactory context=new XmlBeanFactory(new ClassPathResource("spring-config.xml"));
Student result=(Student)context.getBean("student");
}
这时我们再调用一下getBean()方法,我们再运行程序
由此我们可以得出当我们去使用BeanFactory的时候,我们发现只有当我们去取这个对象的时候,我们才会真正去加载并创建它
区别:(1)BeanFactory是 ApplicationContext的父类,其功能和方法相较于ApplicationContext要更少,这样效率、性能会高
(2)ApplicationContext一次加载并实例化所有的Bean对象,而BeanFactory是能用到那个Bean对象再去加载初始化这个对象的,这样节省空间,但效率低
4.Spring存取对象的基本流程:
1.Spring读取Bean流程:先扫描xml文件配置,从配置中或注解中获取Bean对象的定义信息,然后把它注册到Spring容器中
2.Spring加载并实例化Bean:先给Bean对象分配空间,然后进行初始化,然后把它设置到Spring容器中
5.获取bean对象的几种方式
(1)通过id名称获取bean
public static void main11(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
Student result=(Student)context.getBean("student");
result.say();
}
(2)通过类名获取bean:
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-config.xml");
Student result=context.getBean(Student.class);
result.say();
}
当我们通过类名的方式去获取对象的时候,我们发现这个时候,我们不用再进行强转成Student类型了
但是这种方式存在一个问题,如果我们再注册一个Student类的对象在里面
<bean id="student" class="spring.Student"></bean>
<bean id="stu" class="spring.Studedt"></bean>
<bean id="teacher" class="spring.Teacher"></bean>
这时我们再去通过这种方式获取这就存在问题了。
(3)正确的方式应该是通过 id+类名的方式
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
Student student1 = context.getBean("student", Student.class);
Student student2 = context.getBean("stu", Student.class);
student1.say();
student2.say();
}
(4)更简单的存储Bean对象的方式,添加类注解
五大类注解:1.@Controller (控制器,用来验证前端传来的数据是否正确,如果不正确,返回false)防止别人恶意访问程序,相当于安保系统
2.@Service 服务:负责调度和提供一些方法,但是不实际执行,相当于客服中心
3.@Repository 持久层:和数据层交互,负责实际执行
4.@Component 组件工具类
5.@Configuration 配置项(项目当中的一些配置)
在这里边Compoent是所有这几个类的父类,其他的四个类都继承了这个类,我们随便打开其他四个类里面的一个类看看:
通过在在类外添加注解的方式也能存储Bean对象,但是我们需要在spring-conflig.xml中增加
<content:component-scan base-package="com.gather"></content:component-scan>
base-package表明类所在的包
package com.gather;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Student{
public void say()
{
System.out.println("hello student");
}
}
像这种添加类注解的方式,我们用getBean()的方式来获取的话,那么里面的参数应该如何写呢?其实也是一种类似于Bean名称+类名的方式,如果类名第一个字母大写的话,我们只需把第一个字母变成小写
public class Text {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
Student student=(Student) context.getBean("student",Student.class);
student.say();
}
}
在这里我们看到如果类名第一个字母大写的话,id直接将类名第一个字母小写即可,
如果我们建的类名前两个都是大写的话,这样就不可以了
public class POlice {
public void say()
{
System.out.println("hello police");
}
}
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
POlice police=context.getBean("police",POlice.class);
police.say();
}
如果id直接也是把第一个字母小写的话,我们发现会报错,
这时候id应该直接写类名
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
POlice police=context.getBean("POlice",POlice.class);
police.say();
}
那么为啥是这样呢?我们来看一下这里相关的源码:
Bean命名规则:首字母默认是小写的,如果首字母第一个大写 ,Bean名称需要将第一个字母小写,如果前两个字母都是大写,那么Bean名称就是类名。
在这里我们还需要注意一个问题:
如果在spring-conflig.xml里只有这一种通过添加注解的方式来存取Bean对象
<content:component-scan base-package="com.gather"></content:component-scan>
我们要存取和Bean对象与之对应的类必须在这个包底下或者在这个包的子目录里,另外如果想要访问这个包底下与之对应的所有Bean对象,这些类都要加注解,举个例子:
因为Farmer这个类没在com.gather这个包底下,也不在这个包的子包底下,所以相当于我们没把它注册到Spring容器中,所以就取不到这个对象
那应该如何解决呢?
我们在spring-conflig.xml再加一行Bean注册内容即可
<bean id="farmer" class="Farmer"></bean>
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
Farmer farmer=context.getBean("farmer",Farmer.class);
farmer.say();
}
通过在方法上加Bean注解的方式将Bean对象存储在服务器上,但是在类上我们要加上类注解,因为这样我们是存在一些类不需要去存储在Spring中,这样再去读取扫描和配置文件的时候,可以快速的定位存储在Spring中的类,方便快速取出对象,这样可以提高性能。
@Configuration
public class Use2 {
@Bean
public User getuser2()
{
User user=new User();
user.name="小凯";
user.age=5;
return user;
}
}
但是要注意这里的方法名必须是要存储Bean对象的类名
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
User user=context.getBean("getuser2",User.class);
System.out.println(user.name);
}
这里要注意getBean()方法里的第一个参数是方法名
我们来看一下打印信息
getBean()方法里面第一个参数也就是Bean名称是一个方法名,感觉怪怪的,其实我们是可以重新起一个名字的
@Configuration
public class User1 {
@Bean(value = "user2")
public User getuser2()
{
User user=new User();
user.name="小凯";
user.age=5;
return user;
}
}
也就是在Bean注解之后用value重新起一个名,getBean()方法里第一个参数也就可以写这个名了
User user=context.getBean("user2",User.class);
但是这里要注意如果重新起了名,getBean()方法里第一个参数就不能再用原来的方法名了(getuser2)
大家在这里想一个问题,如果我们再在另一个类里面写一个和User1里面一模一样的方法,那么当我们再去取得时候
@Configuration
public class User2 {
@Bean//(value="user7")
public User getuser2() {
User user = new User();
user.name = "小中";
user.age = 5;
return user;
}
}
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
User user=context.getBean("getuser2",User.class);
System.out.println(user.name);
}
这取决于谁先注入,谁先被加载,谁后注入,后注入的会覆盖先注入的,我们再来写段代码看看,
我们在两个类前面分别加上两个@Order(10) 、@Order(20) 这里的注解表示的是谁先注入,数字越小表示注入的越早,一开始是User1里面的先注入,当我们把数值改一@Order(20)@Order(10)
这时就会产生不同的结果了。
取Bean更简单的方式使用@Autowired、Resource
@Autowired 注解表示将需要的对象从Spring容器里取出来,
1.属性注入
我们先建立一个Police类
@Configuration
public class Police {
public String name;
public int age;
public void say()
{
System.out.println("hello police");
}
}
然后再创建一个UsePolice类,我们通过属性注入的方式将Police对象注入,
@Configuration
public class UsePolice {
@Autowired
Police police;
public void getpolice()
{
police.say();
}
}
然后我们拿到UsePolice这个类型的对象
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
UsePolice usePolice=context.getBean("usePolice",UsePolice.class);
usePolice.getpolice();
}
属性注入的优点:简单方便 弊端:(1)不符合单一设计的原则,我们可以将多个类型的对象共同注入(2)不能注入被final修饰的对象
因为final修饰的变量要么在后面直接赋值,要么利用构造方法赋值。
(3) 只适用于Ioc容器,不具备通用性
2.Setter注入
@Configuration
public class UsePolice2 {
public Police police;
@Autowired
public void setPolice(Police police) {
this.police = police;
}
public void getpolice()
{
police.say();
}
}
Setter方法注入的优点:(1)符合单一设计的原则 缺点:(1)不能注入被final修饰的对象
(2)使用Setter注入的对象可能被修改 比如我们在getPolice()方法里将police置为null
@Configuration
public class UsePolice2 {
public Police police;
@Autowired
public void setPolice(Police police) {
this.police = police;
}
public void getpolice()
{
this.police=null;
police.say();
}
}
3.构造方法注入
@Component
public class UsePolice3 {
public Police police;
@Autowired
public UsePolice3(Police police)
{
this.police=police;
}
public void getpolice()
{
police.say();
}
}
构造方法注入的特点:如果当前类里面只有一个构造方法的话,那么@Autowired可以被省略
构造方法注入优点分析:1.能注入被final修饰的对象
2.构造方法只执行一次,注入对象不会再被修改
3.构造方法注入不止适用于Ioc容器,具有通用性。
4.构造方法注入会将注入的对象完全初始化
缺点:构造方法里可以传多个参数,可能会违背单一设计原则。
与@Autowired注解作用差不多的还有@Resource注解
@Resource同样可以属性注入和Setter注入,但是如果是构造方法注入就会报错
接下来我们来思考一个问题:如果有两个Police对象,这时注入的是谁呢?我们启动一下
@Component
public class Useuser4 {
@Bean(value="police1")
public Police getpolice()
{
Police police=new Police();
police.name="小海";
police.age=9;
return police;
}
@Bean
public Police getpolice2()
{
Police police =new Police();
police.name="小小";
police.age=9;
return police;
}
}
Component
public class Usepolice {
@Resource
public Police police;
public void say()
{
police.say();
System.out.println(police.name);
}
}
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("spring-conflig.xml");
Usepolice useuser4=context.getBean("usepolice",Usepolice.class);
useuser4.say();
}
打印结果:
我们发现会报错,这是因为Resource先根据名称去查,然后再根据类型去查,
这里的名称也就是police ,我们发现注册的两个Police实例都不是这个名称,然后再根据Police类型去找,发现两个Police实例也不是以Police为名称的
这个问题的解决办法就是在Resource后面加上具体的Bean对象的名称
@Resource(name="police1")
public Police police;
这时候就指定是注入police1这个对象了
那使用@Autowired能不能指定指定的对象呢?其实也是可以的
@Autowired
@Qualifier(value="police1")
总结:@Resource注解和@Autowired的区别
(1)@Autowired来自Spring @Resource来自jdk的注解
(2)@Autowired 支持属性注入、Setter注入、和构造方法注入,@Resource不支持构造方法注入
(3)相较于@Autowired@Resource可以设置更多的参数可以在后面指定name,依次来获取Bean
Bean的作用域