目录

Spring一

Spring(一)

bean对象的存储和读取

1.创建一个bean对象,在java当中一个对象被使用多次,就可以称为Bean。

package com.spring.demo;

public class Student {
    public void sayHi(){
        System.out.println("hi student");
    }
}

2.将bean存储到Spring容器当中

<!-- 将 bean(com.spring.demo.Student)存到 Spring 容器中,它的名称叫做 student -->
    <bean id="student" class="com.spring.demo.Student"></bean>

解释说明:

https://i-blog.csdnimg.cn/direct/bdd6260c5a014bf985f9bbec33de97dc.png

3.从Spring容器当中读取bean对象

import com.spring.demo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        //1.创建Spring上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        //2.从Spring容器当中获取到Bean对象
        Student student = (Student) context.getBean("student");

        //3.使用Bean对象
        student.sayHi();
    }
}

运行结果:

https://i-blog.csdnimg.cn/direct/245a118aeb9f406dbc69f123b594280c.png

注意细节问题,如下图所示

https://i-blog.csdnimg.cn/direct/f09d5f6bdb044424a3c1f3aed55a7f2c.png

https://i-blog.csdnimg.cn/direct/50570715fc334da1a9917b7f1f0ac637.png

除了上述使用的 ApplicationContext接口还可以使用 BeanFactory接口来创建Spring上下文
  //1.创建Spring上下文
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml"));

        //2.从Spring容器当中获取到Bean对象
        Student student = (Student) beanFactory.getBean("student");

        //3.使用Bean对象
        student.sayHi();

运行结果:

https://i-blog.csdnimg.cn/direct/91d455bda4994bfdb2c2720a29d4ba1d.png

问题既然它们都能够实现同样的功能为什么有了 ApplicationContext还要有 BeanFactory呢

请看如下代码:

package com.spring.demo;

public class Student {
    public Student() {
        System.out.println("Student构造方法被执行");
    }

    public void sayHi() {
        System.out.println("hi student");
    }
}


public class App {
    public static void main(String[] args) {
        //1.得到Spring上下文
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");
}

ApplicationContext运行结果:

https://i-blog.csdnimg.cn/direct/9c5a6599845d4c2abd5f339854d0a058.png

得出结论:

ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");这行代码执行结束,就会加载对应的Bean对象(饿加载模式)。

对应的:使用BeanFactory下面行这行代码执行结束,并不会对构造方法进行初始化。

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml")); (懒加载模式)。


当程序执行到这行代码的时候才会有初始化的操作Student student = (Student) beanFactory.getBean("student");

ApplicationContext 和 BeanFactory的区别

1.从继承关系上来说

 BeanFactory提供了基础的访问容器的能,ApplicationContext属于 BeanFactory 它除了继承了 
 BeanFactory 的所有功能之外,还添加了对国际化支持资源访问以及事件传播等⽅⾯

2.二者的加载时机不同:
ApplicationContext是饿加载它会一次性将xml文件中的Bean对象进行加载,之后的读取效率会很高而BeanFactory是懒加载只有调用getBean的时候,才会去加载对应的Bean对象因此效率较低

3:从本质上来说二者并没有谁好谁坏之分,他们测重点不同,ApplicationContext效率高是通过牺牲内存为代价的,而BeanFactory效率低的同时也节约了内存空间 

获取Bean对象的三种方式

1.通过名称获取

https://i-blog.csdnimg.cn/direct/efbd3d9801a249efaefc0fafb7d1df4b.png

2.通过类型获取

https://i-blog.csdnimg.cn/direct/b0c020263b25482a9f920b1c367d753f.png

通过类型获取引发的问题是:如果Spring容器当中一个类型存储了多个实例,那么使用类型获取就会抛 NoUniqueBeanDefinitionException

https://i-blog.csdnimg.cn/direct/c5342d39bf834b1a843d005ca5e7fc4b.png

https://i-blog.csdnimg.cn/direct/e71b4b14e8824b099f9d6245290f88f5.png

  1. 通过名称+类型获取
Student student = context.getBean("student", Student.class);

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

在 Spring 中使⽤注解可以更简单的存储和读取对象。

在进行Bean对象的存取的时候,需要做一下前置工作, 配置扫描路径 。想要将对象成功的存储到 Spring 中,我们需要配置⼀下存储对象的扫描包路径,只有被配置的包下的所有类,添加了注解才能被正确的识别并保存到 Spring 容器中。在 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.demo"></content:component-scan>
</beans>

使用类注解(五大类注解)

  • @Controller:控制器:用于验证用户请求数据的合法性。(类似于安保系统)
  • @Service:服务:编排和调度具体执行方法的。(类似于客服中心)
  • @Repository:持久层:和数据库进行交互 (类似于执行者)
  • @Component:组件(工具类)
  • Configuration:配置项(项目中的一些配置)

@Controller实现Bean存储:

package com.java.demo;

import org.springframework.stereotype.Controller;

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

注意问题:一定要把注解加上,不加注解会抛异常,如下图所以

https://i-blog.csdnimg.cn/direct/89cc9f05e07b4334b2f26e9d3519f70e.png

读取Bean:

import com.java.demo.StudentController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        //2.获取Bean
        StudentController studentController = context.getBean("studentController", StudentController.class);

        //3.使用Bean
        studentController.sayHi();
    }
}

@Service实现Bean存储

package com.java.demo;

import org.springframework.stereotype.Service;

@Service

public class StudentService {
    public void sayHi(){
        System.out.println("hi");
    }
}

读取Bean:

import com.java.demo.StudentService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        //1.获取Spring上下文对象
        ApplicationContext context =
                new ClassPathXmlApplicationContext("spring-config.xml");

        //2.获取Bean
        StudentService studentService = context.getBean("studentService", StudentService.class);

        //3.使用Bean
        studentService.sayHi();
    }
}

剩下三个类注解,在使用上和上述两个注解的使用完全一样。

注意事项

  • 先配置扫描路径,在存放Bean到Spring容器中。
  • 在component-scan下不要忘记加五大类注解,否则将会抛异常。
  • 标签可以和component-scan一起使用。
  • component-scan下的所有子包下的类只要加了五大类注解,同样可以将对象存储到Spring中
  • 五大类注解不可以不在component-scan包下。

五大类注解之间的关系

如下图所示:

https://i-blog.csdnimg.cn/direct/b453c976fe8947478b03ddb7ec3a5862.png

可以和component-scan 一起使用

https://i-blog.csdnimg.cn/direct/de43cc3233b44055bb42975f2250b902.png

有时候,某个类放在扫描路径下觉得不合适,但又想将这个对象存放到Spring容器当中,为了满足这种场景,就需要扫描路径和传统的类名+classPath结合使用。

为什么要有这么多注解呢?

虽然它们都能实现相同的功能,但它们也有不同的之处,注解很重要的一个功能就是让开发者一看到注解,就知道这个注解的用途。比如:

  • @Controller:表示业务逻辑层
  • @Service:服务层
  • @Repository:持久层
  • @Configuration:配置层

程序的工程分层,调用流程如下:

https://i-blog.csdnimg.cn/direct/b4f875b206674d5583333d5b8c558d5b.png

阿里在标准分层的基础之上,又进行了划分 ,如下图所示:

https://i-blog.csdnimg.cn/direct/322c85a586ea471ea4d0283c75dcad39.png

Bean的命名规则

源码展示:

https://i-blog.csdnimg.cn/direct/2bd75933cdd848249bb0e435d43d76e2.png

方法注解 @Bean

类注解是把注解加在类上,方法注解是将注解加在方法上。

有时候我们需要将一个对像作为返回值,然后交给Spring容器来托管,就可以使用这个@Bean。

代码实例:

1.先创建一个是实体类

package com.java.demo.entity;

public class User {
    private Integer uid;
    private String username;
    private Integer age;

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "uid=" + uid +
                ", username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}

2.将返回的对象存入Spring容器当中

package com.java.demo.component;

import com.java.demo.entity.User;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class UserBeans {
    @Bean(name = {"u1","u2"})//Bean重命名
    public User user1() {
        User user = new User();
        user.setUsername("张三");
        user.setAge(18);
        user.setUid(1);
        return user;
    }
}

说明:虽然叫方法注解,但是它要搭配上类注解,才能成功的存入Spring容器当中。

3.从Spring容器当中取出bean对象

import com.java.demo.controller.UserController;
import com.java.demo.entity.User;
import com.java.demo.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class APP {
    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());
    }
}

   说明1.@Bean的命名规则和上述的五大类注解的命名规则不同默认情况下@Bean存储对象的
          名称 = 方法名
      
        2.在使用Bean注解的时候,需要搭配上上述的五大类注解一起使用

        3.@Bean可以重命名,@bean进行重命名之后,默认方法名的方式无法获取到bean对象




      

https://i-blog.csdnimg.cn/direct/0c19c972ebee4697bccf34ea23cd5e28.png

https://i-blog.csdnimg.cn/direct/15460b45dca8400aa52410852998ca30.png

对象注入

//对象注入:将存储在Spring容器当中的bean对象,注入到当前类中。对象注入有三种方式:


//1.属性注入

@Autowired
 private UserService userService;


//2.setter注入

private UserService userService;

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



//3.构造方法注入


 private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
        userService.age = 20;
    }

三种注入对象的优缺点分析:

1.属性注入:

https://i-blog.csdnimg.cn/direct/77d4ab7aa1134a1aa2fe52bb8161f99d.png

2.setter注入:

https://i-blog.csdnimg.cn/direct/0de600a7560b44b8b4e4e35abc22652f.png

3.构造方法注入:

https://i-blog.csdnimg.cn/direct/ade8f9468f904f9a9d9a184cb8959f7a.png