写点什么

Spring 你牛个啥,我承认刚才说话我声音有点大

作者:zxhtom
  • 2022 年 7 月 05 日
  • 本文字数:5492 字

    阅读完需:约 18 分钟

Spring你牛个啥,我承认刚才说话我声音有点大




spring 彻底改变了 java 世界观。spring 解决了 java 对象管理问题,今天我们来看看 spring 创建对象的方式有哪些至今还不知道的吧

注册 bean 的几种方式(IOC)

BeanDefinition



  • 我们查看类图可以看出,BeanDefinitionRegistry下有三个实现类。spring 为我们提供了一个默认的BeanDefinition注册工厂DefaultListableFactory 。 为什么说他是默认的不仅仅是因为名字里出现了 Default 字样。而是在AnnotationConfigApplicationContext中默认使用的就是 DefaultListableFactory。在注解式开发汇总AnnotationConfigApplicationContext上下文是经常使用的。他也可以理解成 spring 容器。

配置类 Config

  • 相信大家都是用过 springboot。在 springboot 中首先需要一个启动类。这个启动类上会添加各种各样的注解进行修饰。其实他就是一个配置的入口。相当于 spring 中的 xml 配置文件。

  • 为了演示我们这里也需要一个这样的配置类。告诉 spring 哪些类他需要进行装载解析。


@ComponentScan(value = "com.zxhtom.cloud.order.spring")public class Config {}
复制代码


  • Config 的作用就是告诉 spring 去扫描com.zxhtom.cloud.order.spring包下带有 spring 注解的类及配置类

生成 bean

  • 相信大家对@Bean@Component@Service这些注解都不陌生。这些都是 spring bean 的注解。但是这些注解的背后又是什么呢。对!就是本章节的主题BeanDefinition 。 spring 的 bean 的注册都是通过它来完成的。


//首先获取容器上下文AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);//生成java类对应的BeanDefinitionBuilderBeanDefinitionBuilder builder = BeanDefinitionBuilder        .genericBeanDefinition(Student.class);//将BeanDefinition注册到该spring容器上context.registerBeanDefinition("student",builder.getBeanDefinition());//尝试获取Object orderController = context.getBean("student");System.out.println(orderController);
复制代码



  • 上面简单几行就完成了 springbean 的注册。在AnnotationConfigApplicationContext中,我们看到他是继承了GenericApplicationContext这个类的。而这个类中默认的是上面我们提到的DefaultListableFactory

  • 这也是我们在开始放置的一张图。到这里我们知道 BeanDefinition 是 spring 注册 bean 的元素。而BeanDefinitionRegistry是注册真正的工作者。他负责解析BeanDefinition将对应的 Java 对象转换成 spring 的 bean。这中间还有很多很多的细节处理。这里我们不做展开啦。

FactoryBean


  • FactoryBean是一个接口,在 java8 中我们只需要实现getObjectgetObjectType两个方法。前者是生成对象后者是返回对象 Class 对象。

  • 下面我们通过FactoryBean来创建一个 springbean .


@Datapublic class User {    private String name;}
复制代码


  • ①首先我们编写一个普通的 Java 类 User 。不要添加 spring 注册 bean 的注解


public class UserFactoryBean implements FactoryBean<User> {    @Override    public User getObject() throws Exception {        User user = new User();        user.setName("hello");        return user;    }
@Override public Class<?> getObjectType() { return User.class; }}
复制代码


  • ②然后在编写一个实现了FactoryBean接口的实现类。在 getObject 方法中我们构造一个 User 对象并返回。


public class BeanTest {    public static void main(String[] args) {        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();        BeanDefinitionBuilder builder = BeanDefinitionBuilder                .genericBeanDefinition(UserFactoryBean.class);        context.refresh();        context.registerBeanDefinition("user", builder.getBeanDefinition());        System.out.println("获取user:"+context.getBean("user"));        System.out.println("获取userFactoryBean:"+context.getBean("&user"));    }}
复制代码


  • ③最后我们构建一个UserFactoryBean对应的BeanDefinition对象。值得注意的是 UserFactoryBean 的 BeanDefinition 会向 spring 注册两个对象到 spring 容器中。一个是 getObject 方法中的对象。另外一个就是UserFactoryBean自己本身。

  • 在 spring 容器中是通过 KV 形式保存对象信息的,两个对象是不可能对应同一个 key 的。上面注册进来的名称是 user 。



  • FactoryBean作用就是将负责的 bean 生成过程进行代码话。 比如上面是构建一个 User 对象注册到 spring 容器。这种需求我们直接在 User 类上添加@Component并在 Springboot 启动类上添加扫描路径就可以了。

  • 但是如果 User 对象中的 name 在启动是需要将当前时间赋值给 name, 这种需求我们就不好通过 spring 提供的注解配置了。但是通过FactoryBean就可以很好的解决了。因为我们通过代码很容器就获取到时间并进行赋值。

  • FactoryBean在 spring 中的地位也是很高的。在 mybatis 框架中如何将 Mapper 接口注册到 spring 容器就是利用他的功能。因为 spring 中是无法注册接口的。mybatis 将接口生成代理类注册到 spring 容器。在执行这些代理类的时候在根据 Mapper 对象的 xml 里的 sql 进行 SqlSession 执行 sql 进行数据的解析。

Supplier


  • GenericApplicationContext类中我们发现registryBean方法中有个重载的方法需要参数 Class、Supplier、BeanDefinitionCustomer。


public static void main(String[] args) {    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();    context.refresh();    context.registerBean("user", User.class);    User user = (User) context.getBean("user");    System.out.println(user.getName());}
复制代码


  • 还是上面的需求,我需要注册是将当前时间赋值给 User#name 属性。这个时候常规操作是没法满足需求的。这个时候除了上面提到的FactoryBean以外,我们还可以通过 Supplier 来初始化。


public static void main(String[] args) {    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();    context.refresh();    context.registerBean(User.class, new Supplier<User>() {        @Override        public User get() {            User user = new User();            user.setName(new Date().toString());            return user;        }    }, new BeanDefinitionCustomizer() {        @Override        public void customize(BeanDefinition bd) {            bd.setPrimary(true);            System.out.println(bd);        }    });    User user = (User) context.getBean("user");    System.out.println(user.getName());}
复制代码


  • 上述代码实现了 User 对象属性初始化注册。并对 BeanDefinition 进行加强更新。在 Spring 中 Customizer 往往代码封装的意思。BeanDefinitionCustomizer就是对BeanDefinition对象的封装方便对他们进行二次操作。

spring AOP

  • AOP 全称 Aspect Oriented Programming 的缩写。在 spring 中我们已经习惯了面向切面编程了。切面真的帮助我们实现了很多帮助。他将我们重复性的工作进行抽离,是的我们整体的业务不再线性的编程了。最终我们在开发过程就会变成模块-->aop-->模块

概念

  • 在 aop 中我们需要了解到几个专有名词

  • Aspect : 申明切面

  • Joint point : 表示连接点。对异常处理

  • Pointcut : 切点。定义拦截点。由点生面

  • Advice : 在切点上进行增强,对执行点进行包装

  • Target : 代理对象的真实对象

  • Weaving: 将 Aspect 连接起来

spring 容器的认识

  • 上面我们演示的 spring 的两大特性。IOC+AOP。 其中 IOC 就是通过反射将 java 对象注册到容器中。那么这个容器到底是什么个东西。这里我们就简单的理解成 KV 。 内部其实就是一个 Map. key 就是 java 对象在容器中的 beanName。value 就是 java 对象本身.


授人以鱼不如授人以渔,Spring 的强大相信做过 Java 开发的都是知道。今天我们开始 Spring 相关课程的第一话--纵观全局今后我们也是从这个五个方面进行入手,由于探讨框架本身存在很多未知数,里面的总结也肯定是参考别的文献的。个人总结

Spring 结构

Core Container

Spring 中的 Core Container(核心容器)包含有 Core、Beans、Context 和 Expression Language 模块。Core 和 Beans 模块是框架的基础部分,提供 IoC(反转控制)和依赖注入特性。这里的基础概念是 BeanFactory,它对 Factory 模式的金典实现来消除对程序性单利模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。

Core

core 模块主要包含 Spring 框架基本的核心工具类,Spring 的其他组件都需要使用这个包里的类。core 相当于是底层文件,任何 spring 的产品都是建立在 core 上的。

Beans

Beans 在 Core 的基础上进行了功能的扩展它包含访问配置文件,创建和管理 bean 以及进行控制反转、依赖注入操作相关的所有类。Beans 相当于是功能性的提供。所有的 spring 项目都用到这个功能。这里引入了 Spring 重大特性之一的依赖注入(控制反转)

Context

Context 模块构建于 Core 和 Beans 模块基础之上,提供了一种类似于刑 DI 注册器的框架式的对象访问方法 。 Context 模块继承了 Beans 的特性,为 Spring 核心提供了大量扩展,添加了对国际化(例如资源绑定)、事件传播、资源加载和对 Co ntext 的 透明创建的支持 。 Context 模块同时也支持 J2EE 的一些特性, 171) :Ji.口 EJB 、几仪和基础的远程处理 。 ApplicationContext 接口是 Context 模块的关键 。

Expression Language 模块提供了一个强大的表达式语言用于在运行时查询和操作对象。

Expression Language 模块提供了强大的表达式语言,用于在运行时查询和操纵对象 。它是 JSP 2.1 规范中定义的 unifed expression language 的扩展 。 该语言支持设直/获取属性的值,属性的分配,方法的调用,访问数组上下文(accessiong the context of arrays )、容器和索引器、逻辑和算术运算符、命名变量以及从 S prit 屯的 IoC 容器中根据名称检索对象 。 它也支持 list 投影、选择和一般的 list 聚合

Data Access/Integration

Data Access/Integration 层包含而 BC 、 ORM 、 OXM 、几础和 Transaction 模块 。


  • JDBC 模块提供了一个 JDBC 抽象层,它可以消除冗长的 JDBC 编码和解析数据库厂商特有的错误代码。 这个模块包含了 Spring 对 JDBC 数据访问进行封装的所有类。

  • ORM 模块为流行的对象-关系映射 API,如 JPA、JDO、Hibernate、Mybatis.提供了一个交互层。利用 ORM 封装包,可以混合使用所有 Springboot 提供的特性进行 OR 映射 Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO 、Hibernate 和 iBatisSQL Map 。 所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构

  • OXM 模块提供了一个对 ObjecνXML 映射实现的抽象层, Object/XML 映射实现包括 JAXB 、 Castor 、 XMLBeans 、 JiBX 和 XStrearn 。。

  • JMS ( Java Messaging Service )模块主要包含了 一些制造和消 费消息的特性 。

  • Transaction 模块支持编程和声明性的事务 管理,这些事务类必须实现特定的接 口,并且对所有的 POJO 都适用 。

Web

Web 上下文模块建立在应用程序上下文模块之上。为基于 Web 的应用程序提供了上下文。所以 Spring 框架支持与 Jakarta Struts 集成。Web 模块还简化了处理大部分请求以及讲请求参数绑定到域对象工作,Web 层包含了 Web,Servlet、Struts、Porlet 模块。


  • Web 模块:童工基础的面向 web 的集成特性。多文件上传、使用 listeners 初始化 IOC 容器、容器上下文。还包括 Spring 远程支持中 Web 的相关部分。

  • Servlet 模块: 该模块包含 Spring 的 model-view-controller ( MVC)实现 。 Spring 的 MVC 框架使得模型范围内的代码和 web forms 之间能够清楚地分离开来,并与 Spring 框架的其他特性集成在一起

  • Struts 模块:该模块提供了对 Struts 支持,是的类在 Springboot 容器中能够与一个典型的 Struts web 层集成在一起,spring3.0 之后已被抛弃

  • Porlet 模块: 提供了用于 Portlet 环境和 Web——servlet 模块的 Mvc 的实现

Aop

AOP 模块提供了 一个符合 AOP 联盟标准的面向切面编程的实现,它让你可以定义例如方法拦截器和切点,从而将逻辑代码分开,降低它们之间的调合性 。 利用 source-level 的元数据功能,还可以将各种行为信息合并到你的代码中,这有点像 .Net 技术中的 attribute 概念 。通过配置管理特性, SpringAOP 模块直接将面向切面的编程功能集成到了 Spring 框架中,所以可以很容易地使 Spring 框架管理的任何对象支持 AOP 。 Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务 。 通过使用 SpringAOP ,不用依赖 EJB 组件,就可以将声 明性事务管理集成到应用程序中 。Aspects 模块提供了对 AspectJ 的集成支持 。。Instrumentation 模块提供了 class instrumentation 支持和 classloader 实现, 使得可以在特定的应用服务器上使用 。

Test

Test 模块就是在容器内进行单元测试。没啥好说的。


单例池 BeanFactoryApplicationContextAnnotationConfigApplicationContextClassPathXmlApplicationContextFileSystemApplicationContext

总结

  • spring 是个框架,但是现在 spring 已经不仅仅是框架了。我们可以把 spring 理解成一个生态。

  • 在 spring 基础上已经衍生出脚手架 springboot 。 还有在微服务上的 springcloud

  • 而在 springcloud 中有衍生出很多的组件。大多都是借鉴了 netflix 。 比如说 eureka、 zuul 等 。 其中 zuul 已被 springcloud gateway 取代

  • 因为 spring 的设计优秀已经和 mybatis、redis、rabbitmq 这些都是完美的整合了。

  • 本章主要是介绍 spring . 后面也会继续更新 springcloud 专题。 因为在 cloud 中发现对 spring 的基础要求还是很高的。

  • 这个五一先放放 cloud 。 来个 spring 爽爽 。 cloud 五一后再见

发布于: 刚刚阅读数: 3
用户头像

zxhtom

关注

还未添加个人签名 2019.08.19 加入

还未添加个人简介

评论

发布
暂无评论
Spring你牛个啥,我承认刚才说话我声音有点大_7月月更_zxhtom_InfoQ写作社区