Spring相关概念
1.1初始Spring

在这一节,主要通过以下两个点来了解下Spring:

1.1.1Spring家族

官网:https://spring.io,从官网我们可以大概了解到:

Spring能做什么:用以开发web、微服务以及分布式系统等光这三块就已经占了JavaEE开发的九成多。

Spring并不是单一的一个技术,而是一个大家族可以从官网的projects中查看其包含的所有技术。

Spring发展到今天已经形成了一种开发的生态圈,Spring提供了若干个项目每个项目用于完成特定的功能。

Spring已形成了完整的生态圈,也就是说我们可以完全使用Spring技术完成整个项目的构建、设计与开发。

Spring有若干个项目,可以根据需要自行选择,把这些个项目组合起来,起了一个名称叫==全家桶==,如下图所示。

spring boot 反射获取Bean_Powered by 金山文档

说明:

图中的图标都代表什么含义,可以进入https://spring.io/projects网站进行对比查看。

这些技术并不是所有的都需要学习,额外需要重点关注spring Framework、Sprinaboot和springcloud:

spring boot 反射获取Bean_spring_02

  • SpringFramework:Spring框架,是Spring中最早最核心的技术,也是所有其他技术的基础
  • SpringBoot:Spring是来简化开发,而SpringBoot是来帮助Spring在简化的基础上能更快速进行开发。
  • SpringCloud;这个是用来做分布式之微服务架构的相关开发。

除了上面的这三个技术外,还有很多其他的技术,也比较流行,如SpringData,SpringSecurity等,这些都可以被应用在我们的项目中。我们今天所学习的Spring其实指的是==SpringFramework==。

1.1.2了解Spring发展史

接下来我们介绍下springFramework这个技术是如何来的呢?

spring boot 反射获取Bean_java_03

Spring发展史

  • IBM(IT公司-国际商业机器公司)在1997年提出了E]B思想早期的AVAEE开发大都基于该思想。
  • Rodjohnson(java和j2EE开发领域的专家)在2002年出版的Expert one-on-one J2EE Desigh and Development,书中有阐述在开发中使用EJB该如何做。
  • RodJohnson在2004年出版的Expert one-on-one J2EE Deveopment without B,书中提出了比EB思想更高效的实现方案,并且在同年将方案进行了具体的落地实现,这个实现就是Spring1.0。
  • 随着时间推移,版本不断更新维护,目前最新的是Spring5
  • Spring1.0是纯配置文件开发
  • Spring2.0为了简化开发引入了注解开发,此时是配置文件加注解的开发方式
  • Spring3.0已经可以进行纯注解开发,使开发效率大幅提升,我们的课程会以注解开发为主
  • Spring4.0根据]DK的版本升级对个别API进行了调整
  • Spring5.0已经全面支持]DK8,现在Spring最新的是5系列所以建议大家把IDK安装成18版

本节介绍了Spring家族与Spring的发展史,需要大家重点掌握的是:

  • 今天所学的Spring其实是Spring家族中的Spring Framework
  • SpringFramework是Spring家族中其他框架的底层基础学好Spring可以为其他Spring框架的学习打好基础

1.2Spring系统架构

前面我们说spring指的是Spring Framework,那么它其中都包含哪些内容以及我们该如何学习这个框架?

针对这些问题,我们将从系统架构图和课程学习路线来进行说明:

1.2.1系统架构图

  • SpringFramework是Spring生态圈中最基础的项目,是其他项目的根基。
  • SpringFramework的发展也经历了很多版本的变更,每个版本都有相应的调整。

spring boot 反射获取Bean_前端_04

  • SpringFramework的5版本目前没有最新的架构图,而最新的是4版本,所以接下来主要研究的是4的架构图

spring boot 反射获取Bean_java_05

  • Data Access;数据访问
  • Data Integration:数据集成
  • Web: Web开发
  • AOP:面向切面编程
  • Aspects:AOP思想实现
  • Core Container:核心容器
  • Test:单元测试与集成测试

核心层
  • CoreContainer:核心容器,这个模块是Spring最核心的模块,其他的都需要依赖该模块
AOP层
  • AOP:面向切面编程,它依赖核心层容器,目的是==在不改变原有代码的前提下对其进行功能增强==
  • Aspects:AOP是思想Aspects是对AOP思想的具体实现
数据层
  • DataAccess:数据访问,Spring全家桶中有对数据访问的具体实现技术
  • Dataintegration:数据集成,Spring支持整合其他的数据层解决方案,比如Mybatis
  • Transactions事务,Spring中事务管理是SpringAP的一个具体实现,也是后期学习的重点内容
Web层
  • 这一层的内容将在SpringMVC框架具体学习
Test层
  • Spring主要整合了Junit来完成单元测试和集成测试

1.2.2课程学习路线

介绍完Spring的体系结构后,从中我们可以得出对于Spring的学习主要包含四部分内容,分别是:

  • ==Spring的IOC/DI==
  • ==Spring的AOP==
  • ==AOP的具体应用事务管理==
  • ==IOC/DI的具体应用整合Mvbatis==

spring boot 反射获取Bean_Java_06

对于这节的内容,大家重点要记住的是Spring需要学习的四部分内容。接下来就从第一部分开始学起。

1.3Spring核心概念

在Spring核心概念这部分内容中主要包含IOC/DI、IOC容器和Bean那么问题就来了,这些都是什么呢?

Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。 作为轻量级的框架,它大大简化了Java企业级开发,提供了强大、稳定的功能。它也是一个三层架构,提供了一个集成框架,在Web层有Spring MVC,在业务层有Spring Core,在持久层有Spring ORM。Spring框架的核心就是IoC(控制反转)和AOP(面向切面编程)。

Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。

目的:解决企业应用开发的复杂性

功能:通过IOC和AOP等机制,能够对项目中的组件进行解耦合管理,建立一个低耦合的应用框架,并提供了更多的企业应用功能

范围:任何Java应用

它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起一个连接作用。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

2.Spring反射

2.1什么是反射

  1. Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
  2. Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。

2.2反射的原理

下图是类的正常加载过程、反射原理与class对象:

Class对象的由来是将.class文件读入内存,并为之创建一个Class对象

spring boot 反射获取Bean_Java_07

2.3反射的优缺点:

  1. 优点:
  • 在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。

2、缺点:

  • 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
  • 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。

3.反射的用途:

  1. 反编译:.class-->.java
  2. 通过反射机制访问java对象的属性,方法,构造方法等
  3. 当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他的属性和方法是,一按点号,编译器就会自动列出他的属性或者方法,这里就是用到反射。
  4. 反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。
  5. 例如,在使用Strut2框架的开发过程中,我们一般会在struts.xml里去配置Action,比如
<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute">   
    <result>/shop/shop-index.jsp</result>           
    <result name="error">login.jsp</result>       
</action>

比如我们请求login.action时,那么StrutsPrepareAndExecuteFilter就会去解析struts.xml文件,从action中查找出name为login的Action,并根据class属性创建SimpleLoginAction实例,并用Invoke方法来调用execute方法,这个过程离不开反射。配置文件与Action建立了一种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后StrutsPrepareAndExecuteFilter会去动态地创建Action实例。

比如,加载数据库驱动的,用到的也是反射。

Class.forName("com.mysql.jdbc.Driver"); // 动态加载mysql驱动

4.反射机制常用的类:

  • Java.lang.Class;
  • Java.lang.reflect.Constructor;
  • Java.lang.reflect.Field;
  • Java.lang.reflect.Method;
  • Java.lang.reflect.Modifier;

反射对应到Java中的类库就是在java.lang.reflect下,在该包下包含着Field、Method和Constructor类。

  • Field:
  • Method:
  • Constructor: 表示的是类的构造方法的信息

在反射中常用的方法,我这里做了一个列举,当然更加详细的可以查官方的API文档进行学习。

方法名

作用

getConstructors()

获取公共构造器

getDeclaredConstructors()

获取所有构造器

newInstance()

获取该类对象

getName()

获取类名包含包路径

getSimpleName()

获取类名不包含包路径

getFields()

获取类公共类型的所有属性

getDeclaredFields()

获取类的所有属性

getField(String name)

获取类公共类型的指定属性

getDeclaredField(String name)

获取类全部类型的指定属性

getMethods()

获取类公共类型的方法

getDeclaredMethods()

获取类的所有方法

getMethod(String name, Class[] parameterTypes)

获得类的特定公共类型方法

getDeclaredClasses()

获取内部类

getDeclaringClass()

获取外部类

getPackage()

获取所在包

5.反射机制

Java反射机制 是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种 动态 获取的信息以及动态调用对象的方法的功能称为java语言的 反射机制。

5.1获取Class类对象的三种方式

万物皆对象,包括 类 也有对象,称为 类对象。要想获取类的信息首先要获取 类。

5.2获取Class类对象方式一:

// 通过类的全限定类名(包名+类名)获取类
Class clazz = Class.forName("类的全限定类名(包名+类名)");

5.3获取Class类对象方式二:

// 直接获取类
Class clazz = Object.class;

5.4获取Class类对象方式三:

// 通过实例对象获取其类
Class clazz = object.getClass();

根据类加载机制,运行时一个类仅有一个类对象

5.5Class类的与反射有关的重要方法:

spring boot 反射获取Bean_前端_08

6.反射的基本使用操作:

Java语言允许通过程序化的方式间接对Class的对象实例操作,Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:构造函数、属性和方法等。Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能.

在idea中导入jar包

spring boot 反射获取Bean_前端_09

在src中创建一service包并在service中创建一个接口

spring boot 反射获取Bean_前端_10

package com.zhao.service;

public interface BookService {
void save();
}

在service中创建一个impl包并创建两个类

spring boot 反射获取Bean_Java_11

package com.zhao.service.impl;

import com.zhao.service.BookService;

public class BookServicelmpl implements BookService {


    @Override
    public void save() {
        System.out.println("BookServicelmpl...save");
    }
}
package com.zhao.service.impl;

import com.zhao.service.BookService;

/**
 * 高配版
 */
public class BookServiceVip implements BookService {
    //属性
    public String name;
    protected String sex;
    int age;
    private String address;

    //构造方法
    public BookServiceVip() {
    }

    public BookServiceVip(String name) {
        this.name = name;
    }

    public BookServiceVip(String name, int age, String sex, String address) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.address = address;
    }

    @Override
    public void save() {
        System.out.println("BookServiceVip...save");
    }
}

在src中创建一个servlet包,并在servlet包中创建BookServlet测试类

package com.zhao.servlet;

import com.zhao.service.BookService;
import com.zhao.service.impl.BookServiceVip;
import com.zhao.service.impl.BookServicelmpl;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class BookServlet {
    BookService bookService1 = new BookServicelmpl();
    BookService bookService2 = new BookServiceVip();

    BookServicelmpl b1 = new BookServicelmpl();
    BookServiceVip b2 = new BookServiceVip();

    @Test
    public void save() throws ClassNotFoundException {
        System.out.println("BookServlet...save");
        bookService1.save();

        //根据类的全类名通过Class获得类的Class加载器
        Class cla = Class.forName("com.zhao.service.impl.BookServiceVip");
        //类的加载器可以获得类中的东西--属性(存储数据)、构造方法(创建对象)、功能方法(完成功能)
        //1.获取类中的属性
        Field[] fields = cla.getFields();//只有获取共有的属性
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("--------------");
        Field[] fields1 = cla.getDeclaredFields();//可以获取任意修饰符修饰的属性
        for (Field field : fields1) {
            System.out.println(field);
        }

        System.out.println("--------");
        //2.获取类中的构造方法
        Constructor[] constructors = cla.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }

        System.out.println("--------------");

        Constructor[] constructors1 = cla.getDeclaredConstructors();
        for (Constructor constructor : constructors1) {
            System.out.println(constructor);
        }
    }
}
4.1代码运行结果

spring boot 反射获取Bean_Powered by 金山文档_12

5.创建一个Info.properties配置文件

key=value
className=com.zhao.service.impl.BookServiceVip

6.test02测试类

package com.zhao.servlet;

import com.zhao.service.BookService;
import org.junit.Test;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Properties;

public class Test02 {

    @Test
    public void test() throws Exception {
        //读取配置文件
        //1.通过文件位置获得输入流
//        File file=new File("D:\\2103\\spring\\spring01\\src\\info.properties");
//        InputStream stream=new FileInputStream(file);
        //在类的根路径src加载器配置文件
        InputStream stream = Test02.class.getClassLoader().getResourceAsStream("info.properties");
        //使用Properties加载输入流
        Properties properties = new Properties();
        properties.load(stream);
        //获取配置文件中key值对应的value
        String value = properties.getProperty("key");
        String className = properties.getProperty("className");

        //根据类的全类名通过Class获得类的Class加载器
        Class cla = Class.forName(className);
        //获取类的无参构造器
        Constructor constructor = cla.getConstructor();
        //使用构造器创建对象
        BookService bookService = (BookService) constructor.newInstance();
        //执行对象的方法
        bookService.save();
    }

}
6.1代码运行结果:

spring boot 反射获取Bean_java_13