栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

Spring(一)

Java 更新时间:发布时间: 百科书网 趣学号
一、主要内容
  • Spring框架概述
  • IOC容器
  • AOP容器
  • JdbcTemplate
  • 事务管理
  • Spring5新特性
二、框架概述 2.1 概述
  • Spring是轻量级的开源的JavaEE框架,由Rod Johnson发起
  • Spring可以解决企业应用开发的复杂性
  • Spring有两个核心部分:IOC和AOP
    • IOC:控制反转,把创建对象的过程交给Spring进行管理(之前是手动new一个,Spring帮我们创建对象)。
    • AOP:面向切面,不修改源代码的情况下进行功能增强
  • Spring特点
    • 方便解耦,简化开发
    • AOP编程支持
    • 方便程序测试
    • 方便和其他框架进行整合
    • 方便进行事务操作
    • 降低API开发难度
    • Spring的源码是经典的学习范例
2.2 入门案例
  1. 在IDEA中新建Maven工程,然后导入Spring所需的依赖。

    org.springframework
    spring-context
    5.3.18

核心部分

  1. 创建普通类,在普通类中创建一个普通的方法
public class User {
    public void add(){
        System.out.println("add...");
    }
}
  1. 创建Spring配置文件,在配置文件中配置创建的对象

之前想要实现这个类的对象的创建,直接new这个类,调add方法就行。现在我们把这个过程交给spring来做(可以通过配置文件做到,也可以通过注解做到,这次是案例入门,所以使用配置文件)。

Spring配置文件使用xml格式,new --> XML Configuration File --> Spring Config



    
    

    

  1. 创建测试类,测试
package com.example;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        // 1.加载Spring的配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        // 2.根据id获取配置创建的对象
        User user = context.getBean("user", User.class);

        System.out.println(user);
        user.add();
    }
}

三、IOC容器 3.1 概念和原理 什么是IOC
  • 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
  • 使用IOC的目的:为了降低耦合度
  • 入门案例就是IOC的实现
IOC底层原理
  • XML解析、工厂模式、反射
图解IOC底层原理

目的:将耦合度降低到最低(对象之间调用不可能完全没有耦合度)

原始方式


工厂模式


IOC过程

  1. xml配置文件,配置创建的对象



  1. 有service类和dao类,创建工厂类
class UserFactory{
    public static UserDao getDao(){
        // 1.xml解析
        String classValue = class属性值;
        // 2.通过反射创建对象
        Class clazz = Class.forName(classValue);
        return (UserDao) clazz.newInstance();
    }
}

进一步地降低了耦合度,当UserDao类名更改时,不再需要更改任何的类,只需要更改xml配置文件即可。

原始方式时,当我们更改了UserDao的类名时,那么所有调用该对象的类都得更改,耦合度非常高。

当有了工厂后,只需要更改工厂里的创建对象的类名就解耦了。

再配合xml的配置和反射技术,只需更新xml的配置,就实现了最佳解耦

3.2 接口
  1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。

  2. Spring提供IOC容器实现的两种方式:

    1. BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不提供开发人员使用。

      加载配置文件的时候不会创建对象,在获取对象(使用)时才去创建对象。

    2. ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用(开发中比较常用)。

      加载配置文件时就会把配置文件中的标签对象进行创建。

    Spring通常配合Web进行开发,创建对象这种耗时耗资源的操作最好都放在启动时处理,在服务器启动的时候就去创建这些对象。

    所以选择 ApplicationContext

    做到慢启动,快响应。

3.3 Bean管理(概念) 什么是Bean管理

Bean管理指的是两个操作:

  1. Spring创建对象
  2. Spring注入属性
管理操作有两种方式
  1. 基于xml配置文件方式实现
  2. 基于注解方式实现
3.4 Bean管理(基于xml方式) 基于xml方式创建对象




  1. 在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
  2. 在bean标签中有很多属性,介绍常用的属性:
    • id:唯一标识
    • class:类的全路径(包类路径)
  3. 创建对象时,默认是执行无参构造方法完成对象创建
基于xml方式注入属性

DI:依赖注入,就是注入属性,需要在创建对象的基础之上完成。

第一种方式:使用set方法进行注入

第二种方式:使用有参构造方法进行注入

使用set方法进行注入
  1. 创建类,定义属性和对应的set方法
public class Book {
    private String bookName;
    private String bookAuthor;

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public void setBookAuthor(String bookAuthor) {
        this.bookAuthor = bookAuthor;
    }

    public void print(){
        System.out.println("bookName = " + bookName);
        System.out.println("bookAuthor = " + bookAuthor);
    }
}
  1. 在Spring配置文件中配置对象创建,配置属性注入


    
    
    


测试

public class TestSpring {
    @Test
    public void testBook(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        Book book = context.getBean("book", Book.class);
        System.out.println("book = " + book);
        book.print();
    }
}

使用有参构造方法进行注入
  1. 创建类,定义属性,创建属性对应有参构造方法。
public class Orders {
    private String orderName;
    private String orderAdd;

    public Orders(String orderName, String orderAdd) {
        this.orderName = orderName;
        this.orderAdd = orderAdd;
    }

    public void print(){
        System.out.println("orderName = " + orderName);
        System.out.println("orderAdd = " + orderAdd);
    }
}
  1. 在Spring配置文件中配置对象创建,配置属性注入


    
    
    

===============================或==================================

    
    
    


测试

@Test
public void testOrders(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Orders orders = context.getBean("orders", Orders.class);
    System.out.println("orders = " + orders);
    orders.print();
}

3.5 Bean管理(xml注入其他类型属性) 字面量 null值

    
    

属性值包含特殊符号




    >]]>

注入属性-外部bean
  1. 创建两个类:service类和dao类
public interface UserDao {
    void update();
}
public class UserDaoImpl implements UserDao{
    public void update() {
        System.out.println("dao update ...........");
    }
}
  1. 在service调用dao里面的方法
public class UserService {
    // 创建UserDao类型属性,生成set方法。
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void add(){
        System.out.println("service add ................");
        userDao.update();
    }
}
  1. 在Spring配置文件中进行配置


    
    





测试

@Test
public void testUser(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println("userService = " + userService);
    userService.add();
}

注入属性-内部bean 一对多

部门和员工

  1. 一个部门有多个员工,一个员工属于一个部门。部门是一,员工是多。
public class Dept {
    private String deptName;

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

    @Override
    public String toString() {
        return "Dept{" +
                "deptName='" + deptName + ''' +
                '}';
    }
}
  1. 在实体类中表示一对多关系,员工表示所属部门,使用对象类型属性进行表示。
public class Emp {
    private String empName;
    private String gender;
    // 员工属于哪一个部门,使用对象形式表示
    private Dept dept;

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public void print(){
        System.out.println("empName = " + empName);
        System.out.println("gender = " + gender);
        System.out.println("dept = " + dept);
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empName='" + empName + ''' +
                ", gender='" + gender + ''' +
                ", dept=" + dept +
                '}';
    }
}
  1. 在Spring配置文件中进行配置

    
    
    
    
        
            
        
    


测试

@Test
public void testEmpDept(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
    Emp emp = context.getBean("emp", Emp.class);
    System.out.println("emp = " + emp);
    emp.print();
}

注入属性-级联赋值 注入外部bean
  1. 修改Spring配置文件

    
    
    
    


    


测试

@Test
public void testEmpDept(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
    Emp emp = context.getBean("emp", Emp.class);
    System.out.println("emp = " + emp);
    emp.print();
}

级联赋值

    
    
    
    
    


    

3.6 Bean管理(xml注入集合属性)
  1. 创建类,定义数组、List、Map、Set类型属性。(用Lombok的@Data注解自动配置getter和setter)
@Data
public class Student {
    // 1.数组类型属性
    private String[] courses;
    // 2.list集合类型属性
    private List list;
    // 3.map集合类型属性
    private Map maps;
    // 4.set集合类型属性
    private Set sets;

    public void print(){
        System.out.println(Arrays.toString(courses));
        System.out.println(list);
        System.out.println(maps);
        System.out.println(sets);
    }
}
注入数组类型属性
  1. 在Spring配置文件中进行配置


    
        Java课程
        MySQL课程
    

注入List集合类型属性


    
        张三
        法外狂徒
    

注入Map集合


    
        
        
    

注入Set集合


    
        MySQL
        Redis
    

总的集合类型bean配置


    
    
        
            Java课程
            MySQL课程
        
    
    
    
        
            张三
            法外狂徒
        
    
    
    
        
            
            
        
    
    
    
        
            MySQL
            Redis
        
    


测试

@Test
public void test01(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Student student = context.getBean("student", Student.class);
    student.print();
}

在集合里面设置对象类型值
  1. 创建一个实体类 Course
@Data
public class Course {
    private String cname;
}
  1. 在配置文件中创建三个 Course 对象

    



    



    

  1. 向集合中注入 Course 对象


    
        
        
        
    

把集合注入部分提取出来

在集合里面设置对象类型值只能在内部使用,把集合注入部分提取出来可以公共使用

  1. 在Spring配置文件中引入名称空间 util

  1. 使用 uitl标签 完成list集合注入提取

    
    
    



    


    


    

  1. list集合注入



测试

3.7 Bean管理(FactoryBean)

Spring有两种bean,一种普通bean,另外一种工厂bean(FactoryBean)

普通bean:

在配置文件中定义bean的类型就是它的返回类型




Student student = context.getBean("student", Student.class);
工厂bean:

作用:

一般情况下,Spring通过反射机制利用的class属性指定实现类实例化Bean,在某些情况下,实例化Bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。

FactoryBean 通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。

在配置文件中定义的bean类型可以和返回类型不一样

  1. 第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean

  2. 第二步:实现接口里面的方法,在实现的方法中定义返回的bean类型

public class MyBean implements FactoryBean {
    // 定义返回bean
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("创造对象的工厂");
        return course;
    }

    public Class getObjectType() {
        return null;
    }

    public boolean isSingleton() {
        return false;
    }
}
  1. 第三步:在配置文件中,定义返回类型就是工厂的类


测试

@Test
public void test02(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
    Course course = context.getBean("myBean", Course.class);
    System.out.println("course = " + course);
}

3.8 Bean管理(bean作用域)
  1. 在Spring里面,默认情况下,bean是单实例对象
@Test
public void test01(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Student student1 = context.getBean("student", Student.class);
    Student student2 = context.getBean("student", Student.class);
    System.out.println("student1 = " + student1);
    System.out.println("student2 = " + student2);
}

  1. 在Spring中可以设置是单实例或者多实例

在Spring配置文件bean标签里面有属性:scope,用于设置单实例还是多实例

scope属性值:

  • 第一个值:默认值,singleton,表示单实例对象
  • 第二个值:prototype,表示多实例对象

区别:

  • 单实例是IOC容器启动时就会去实例化bean并添加到容器当中去,每次获取都是从容器中获取同一个对象
  • 多实例是去获取对象的时候才回去实例化bean,每次获取都会去实例化bean

使用工厂bean生成的对象也是多实例的

为什么用单例、多例:

之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;

之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;

用单例和多例的标准只有一个:

当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),用多例,否则单例;

3.9 Bean管理(bean生命周期)

什么是生命周期:

从对象创建到对象销毁的过程

bean的生命周期
  1. 通过构造器创建bean实例(无参构造)
  2. 为bean的属性设置值和对其他bean引用(调用set方法)
  3. 调用bean的初始化的方法(需要进行配置初始化时执行的方法)
  4. bean可以使用了(对象获取到了)
  5. 当容器关闭的时候,调用bean的销毁的方法(需要配置销毁时执行的方法)
演示
  1. 创建演示实体类
public class Orders {
    private String oname;

    public Orders() {
        System.out.println("第一步:无参构造");
    }

    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步:调用set方法");
    }

    public void initMethod(){
        System.out.println("第三步:初始化实例");
    }

    public void destroyMethod(){
        System.out.println("第五步:销毁实例");
    }
}
  1. 配置文件


    

  1. 测试
@Test
public void test03() {
    // 使用Application的实现类
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
    Orders order = context.getBean("order", Orders.class);
    System.out.println("第四步:bean可以使用了");
    System.out.println(order);

    // 手动销毁bean实例
    context.close();
}
  1. 演示情况

bean的后置处理器

加上后置处理器的话,bean的生命周期有7步

  1. 通过构造器创建bean实例(无参构造)
  2. 为bean的属性设置值和对其他bean引用(调用set方法)
  3. 后置处理器的前置方法,把bean实例传递bean后置处理器
  4. 调用bean的初始化的方法(需要进行配置初始化时执行的方法)
  5. 后置处理器的执行方法,传递bean
  6. bean可以使用了(对象获取到了)
  7. 当容器关闭的时候,调用bean的销毁的方法(需要配置销毁时执行的方法)
后置处理器演示
  1. 创建类,实现接口 BeanPostProcessor,并重写两个方法。
public class MyBeanPost implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器的前置方法");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器的后置方法");
        return bean;
    }
}
  1. 修改配置文件


    
    




  1. 测试查看效果

3.10 Bean管理(xml自动装配) 什么是自动装配

根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入。

演示
  1. 创建两个类,emp中使用Dept对象属性
@Data
public class Emp {
    private Dept dept;
}
@Data
public class Dept {

}
  1. 在配置文件中设置自动装配





  1. 测试查看效果
@Test
public void test04() {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
    Emp emp = context.getBean("emp", Emp.class);
    System.out.println(emp);
}

基于xml的自动装配使用地极少,基本是用注解是方式来自动装配。

3.11 Bean管理(外部属性文件)

比如说,一个类中的属性很多,那么配置文件中就要写非常多的 property 标签,并不是很方便,特别是有变化的时候,还需要修改配置文件,而这个文件中很可能还有其他配置,所以改起来不方便。

所以可以把一些固定值或一些相关的值放到一个 properties 文件中,然后把这个文件引入到xml配置文件中(类似Mybatis的数据库信息)。

  1. 直接配置连接池的方式,各种信息都是写死的


    
    
    
    

  1. 引入外部属性文件(properties文件)

新建properties文件,写好jdbc信息。


引入context命名空间




在配置文件中引入properties配置文件




    
    
    
    

3.12 Bean管理(基于注解方式) 什么是注解
  • 注解是代码特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值,…)
  • 使用注解,注解作用在类上面,方法上面,属性上面
  • 使用注解目的:简化xml配置
Spring针对Bean管理中创建对象提供注解
  • @Component:普通注解,都可以用它创建对象
  • @Service:一般用在业务逻辑层(Service层)
  • @Controller:一般用在Web层
  • @Repository:一般用在DAO层

这四个注解功能是一样的,都可以用来创建bean实例。

这几个注解并没有规定一定要放哪一层,只是为了方便开发,但是最好是建议哪层放哪层

基于注解方式实现创建对象(⭐⭐⭐⭐⭐)
  1. 引入依赖

    org.springframework
    spring-context
    5.3.18

  1. 开启组件扫描(要先引入context命名空间)



    
    

  1. 创建类
// 注解内的value属性可以省略不写,默认值是类名称,首字母小写。UserService——userService
// 四个注解都可以
//@Component(value = "userService")   //@Component("userService")
@Service
public class UserService {
    public void add() {
        System.out.println("userService .....");
    }
}
  1. 测试
@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    // 这个bean的名称就是注解里的value,或者默认是类名,首字母小写
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println("userService = " + userService);
    userService.add();
}

组件扫描配置


    




    

基于注解方式实现属性注入(⭐⭐⭐⭐⭐)

常用注解:

  • @Autowired:根据属性类型自动注入(自动装配)
  • @Qualifier:根据属性名称进行注入
  • @Resource:可以根据类型注入,也可以根据名称注入
  • @Value:注入普通类型属性
@Autowired
  1. 创建 UserDao 接口
public interface UserDao {
    void add();
}
  1. 创建类,实现 UserDao 接口,并在实现类上添加创建对象注解
@Repository
public class UserDaoImpl implements UserDao{

    public void add() {
        System.out.println("UserDao add .....");
    }
}
  1. 在UserService注入UserDao对象,在service类添加dao类型属性,在属性上面使用注解。
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public void add() {
        System.out.println("userService add .....");
        userDao.add();
    }
}

spring 4.0开始就不推荐使用属性注入(@Autowired),改为推荐构造器注入和setter注入。

  1. 测试
@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    // 这个bean的名称就是注解里的value,或者默认是类名,首字母小写
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println("userService = " + userService);
    userService.add();
}

@Qualifier

若一个接口有多个实现类,使用@Autowired就会不知道要注入哪个实现类,所以使用根据名称注入

@Qualifier注解要和@Autowired注解一起使用

  1. 再创建一个类,实现 UserDao 接口,UserDaoImpl2
@Repository(value = "userDaoImpl2")
public class UserDaoImpl2 implements UserDao{

    public void add() {
        System.out.println("UserDaoImpl2 add ......");
    }
}
  1. 使用@Qualifier注解
@Service
public class UserService {
    // 两个注解要一起使用,@Qualifier要指定名称
    @Autowired
    @Qualifier(value = "userDaoImpl2")
    private UserDao userDao;

    public void add() {
        System.out.println("userService add .....");
        userDao.add();
    }
}
  1. 测试
@Test
public void test1(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    // 这个bean的名称就是注解里的value,或者默认是类名,首字母小写
    UserService userService = context.getBean("userService", UserService.class);
    System.out.println("userService = " + userService);
    userService.add();
}

@Resource

@Resource可以根据类型注入,也可以根据名称注入

@Service
public class UserService {
	// 根据类型注入
    @Resource
    private UserDao userDao;

    public void add() {
        System.out.println("userService add .....");
        userDao.add();
    }
}
@Service
public class UserService {
	// 根据名称注入
    @Resource(name = "userDaoImpl2")
    private UserDao userDao;

    public void add() {
        System.out.println("userService add .....");
        userDao.add();
    }
}

Spring官方不建议使用@Resource,因为@Resource不是Spring的。

@value

注入普通类型属性

@Service
public class UserService {
    @Value(value = "abc")
	private String name;
}
纯注解开发
  1. 创建配置类,替代xml配置文件
// 标注这个一个Spring的配置类
@Configuration
// 组件扫描
@ComponentScan(basePackages = {"com.example.spring"})
public class SpringConfig {
    
}
  1. 编写测试类
@Test
public void test2(){
    // 加载配置类,和xml不同
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = context.getBean("userService", UserService.class);
    userService.add();
}
  1. 其余注解操作都一样了

参考资源:

B站尚硅谷:https://www.bilibili.com/video/BV1Vf4y127N5?p=24

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/888245.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号