Spring 源码详解(一)_<dependency> <groupid>org.springframework</groupid_带着假发的程序员的博客-程序员秘密

技术标签: spring  java  

一、所需依赖
1、Spring核心依赖
2、Spring DAO依赖
3、Spring Web依赖
4、Spring Test依赖
二、XML命名空间
三、IOC
1、什么是IOC
2、什么是DI
3、DI的实现方式
3.1、构造器注入
3.2、Setter注入
4、IOC容器
4.1、IOC容器的设计
4.2、ApplicationContext
4.3、注解注入方式
4.3.1、@Autowired 自动装配的歧义性
4.3.2、@Autowired 为什么作用在接口上

一、所需依赖

<!-- Spring依赖 -->
    <!-- 1.Spring核心依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
<!-- 2.Spring dao依赖 -->
<!-- spring-jdbc包括了一些如jdbcTemplate的工具类 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <!-- 3.Spring web依赖 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>
    <!-- 4.Spring test依赖:方便做单元测试和集成测试 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.2.9.RELEASE</version>
  </dependency>

1、Spring核心依赖
spring-core、spring-beans、spring-context
2、Spring DAO依赖
spring-jdbc (JDBCTemplate模板)、spring-tx
3、Spring Web依赖
spring-web、spring-webmvc
4、Spring Test依赖
spring-test

二、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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
        
</beans>

三、IOC
1、什么是IOC
“控制反转”, 将创建对象的过程交给Spring, 比如我们不需要了解Redis或Mybatis的构建过程, 只需简单的配置即可使用, 又比如多个团队开发不同组件, 我们不需要其他团队开发的组件构建过程, 我们这需要的时候直接拿来用即可

2、什么是DI
“依赖注入” IOC的实现方式

3、DI的实现方式
构造器注入
Setter注入
接口注入

目前最常用的是构造器注入与Setter注入, 接口注入一般是使用第三方API时使用, 底层Spring都是通过反射来实现的, 这个我们后面再讨论

3.1、构造器注入
创建 Entity实体类

@Data
public class Users {
    
    private Long id;
    private String username;
    private String password;
    private String email;

    public Users(Long id, String username, String password, String email) {
    
        this.id = id;
        this.username = username;
        this.password = password;
        this.email = email;
    }
}

配置XML

<bean id="users" class="com.chenjiaxin.spring.entity.Users">
    <constructor-arg index="0" value="1"/>
    <constructor-arg index="1" value="zhangsan"/>
    <constructor-arg index="2" value="zhangsan123"/>
    <constructor-arg index="3" value="[email protected]"/>
</bean>

3.2、Setter注入
该方式是Spring比较推荐的方式, 优点是灵活性高, 由于当我们构造参数足够多时, 构造器注入就显得十分冗余
首先,默认情况下 要注入的对象必须要有无参构造器

@Data
public class Users {
    
    private Long id;
    private String username;
    private String password;
    private String email;
    // 可以省略, 这里为了说明
    public Users() {
    
    }
}

XML配置

<bean id="users" class="com.chenjiaxin.spring.entity.Users">
    <property name="email" value="[email protected]"/>
</bean>

4、IOC容器
从上面的例子中我们知道IOC的作用, 它可以容纳我们开发的各种Bean

4.1、IOC容器的设计
IOC容器的设计主要依赖于 BeanFactory与ApplicationContext两个接口, 其中 ApplicationContext是BeanFactory的子接口, 换就话说
BeanFactory是IOC最底层的接口, 但是工作中我们一般使用 ApplicationContext, 因为它对BeanFactory的功能又做了许多扩展

  1. BeanFactory源码
public interface BeanFactory {
    
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    <T> ObjectProvider<T> getBeanProvider(Class<T> var1);

    <T> ObjectProvider<T> getBeanProvider(ResolvableType var1);

    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, ResolvableType var2) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    @Nullable
    Class<?> getType(String var1, boolean var2) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

由于这个接口的重要性, 笔者有必要进行一些基本的阐述

  • getBean 的多个方法用于获取配置给Spring IOC容器的Bean, 从参数类型可以看出可以是字符串也可以是Class类型
    isSingleton 判断是否为单例 true 为单例 isPrototype 判断是否为非单例 true 为非单例
    getAliases 获取别名

4.2、ApplicationContext

  1. ApplicationContext源码
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    
    @Nullable
    String getId(); //获取ID

    String getApplicationName(); //获取应用名称

    String getDisplayName(); //获取应用显示名称

    long getStartupDate(); //获取应用启动时间

    @Nullable
    ApplicationContext getParent(); //获取父级应用上下文

    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; //获取bean工厂(DefaultListableBeanFactory)
}

4.2.1、ClassPathXmlApplicationContext
会在启动时加载指定XML配置, 初始化容器, 比如通过上面的 DI进行Setter或构造器注入之后 我们想得到这个Bean可以这样做

public static void main(String[] args) {
    
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
    Users users = context.getBean("users", Users.class);
    System.out.println(users);
}

4.2.2、AnnotationConfigApplicationContext
使用AnnotationConfigApplicationContext可以实现基于Java的配置类加载Spring的应用上下文。避免使用application.xml进行配置。相比XML
配置,更加便捷。

  1. 创建 configuration配置类
@Configuration注解就相当于XML中的<beans/> 标签
@Configuration
public class UserConfig {
    
    @Bean
    public Users getUsers() {
    
        Users users = new Users();
        users.setId(1L);
        users.setUsername("lisi");
        return users;
    }
}
  1. 读取该bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(UserConfig.class); //注册配置类
context.refresh(); //刷新容器
Users bean = context1.getBean(Users.class);

4.3、注解注入方式
组件扫描 @Component && @ComponentScan
自动装配 @Autowired

注解注入 等同于

组件扫描

  1. 在POJO类上面添加 @Component 注解
  2. 添加配置类,使用 @ComponentScan 使用包扫描, 扫描指定包下的 @Component 注解
  3. 使用 AnnotationConfigApplicationContext类获取对象
@Component
public class Users{
    
    @Value("1")
    private Long id;
    @Value("zhangsan")
    private String username;
}

@ComponentScan(basePackages = "com.chenjiaxin")
public class UserConfig {
    
}

public class SpringMain {
    
    public static void main(String[] args) {
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        Users bean = context.getBean(Users.class);
        System.out.println(bean);
    }
}

组件扫描 只能作用在简单数据类型之上, 如果要作用在复杂对象上是不可取的, 比如下面的例子
//角色类

@Data
public class Role {
    
    private Long id;
    private String roleName;
}

//用户类
@Data
public class Users{
    
    private String email;
    private Role role;
}

//XML
<bean id="role" class="com.chenjiaxin.spring.entity.Role">
    <property name="id" value="1"/>
    <property name="roleName" value="管理员"/>
</bean>

<bean id="users" class="com.chenjiaxin.spring.entity.Users">
    <property name="email" value="[email protected]"/>
    <property name="role" ref="role"/>
</bean>

//获取对象
public class SpringMain {
    
    public static void main(String[] args) {
    
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        Users bean = context.getBean(Users.class);
        System.out.println(bean);
    }
}

@Autowired 自动装配 原理是Set注入, 对上方测试代码进行改造

//角色POJO
@Data
@Component
public class Role {
    
    @Value("1")
    private Long id;
    @Value("管理员")
    private String roleName;
}

//用户POJO
@Data
@Component
public class Users{
    
    @Autowired  
    private Role role;
    @Value("[email protected]")
    private String email;
}

//配置注解扫描
@ComponentScan(basePackages = "com.chenjiaxin")
public class UserConfig {
    
}

//测试
public class SpringMain {
    
    public static void main(String[] args) {
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        Users bean = context.getBean(Users.class);
        System.out.println(bean);
    }
}

@Autowired 是按照类型 获取Bean的

public interface BeanFactory {
    
    ...
    <T> T getBean(Class<T> var1) throws BeansException;
    ...
}

4.3.1、@Autowired 自动装配的歧义性
先看下面一个例子, Uservice接口有两个实现类, 在Test中 使用Autowired 会出现歧义性

public interface UserService {
    
    // 读取数据库伪代码业务接口
    Users selectOne();
}

//实现类一
@Service
public class UserServiceImpl implements UserService {
    
   ...
}

//实现类二
@Service
public class UserServiceImplTwo implements UserService {
    
   ...
}

//测试类
@RunWith(SpringRunner.class)
@ContextConfiguration(classes=UserConfig.class)
public class SpringMain {
    
    @Autowired
    private UserService userService;
    
    @Test
    public void  test1() {
    
        System.out.println(userService.selectOne());
    }
}

解决方案:

  • @Primary
  • @Qualifier

方式一: 被 @Primary标注的实现类 ,当spring 进行装配时 会被优先处理。

@Service
@Primary
public class UserServiceImpl implements UserService {
    
  ...
}

方式二: 也可以在装配的时候 强制让spring 按照名称进行装配 也就是XML中bean标签的ID

@Autowired
@Qualifier("userServiceImpl")
private UserService userService;

4.3.2、@Autowired 为什么作用在接口上
如果Spring配置了<context:component-scan base-package=“com.*.service”></context:component-scan>,并且要注入的接口只有一个实现类的话,那么spring框架可
以自动将interface与其实现类组装起来。如果没有配置component scan,那么我们必须在application-config.xml(或等同的配置文件)定义这个bean。
一般情况下一个接口我们只写一个实现类,这个时候我们只需要在实现类上注解@service

@Service
public class UserServiceImpl implements UserService {
    
	……
}

在这种情况下,我们要使用这个实现类的时候也只需要用@Autowired即可 Spring会自动组装userservice与其实现类UserServiceImpl

@Autowired
private Userservice userservice;
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_46784756/article/details/111386594

智能推荐

Train_*Major*的博客-程序员秘密

TrainTrainTrainimport osimport syssys.path.append(r'D:\ubuntu_share\yolov4-pytorch1')import numpy as npimport timeimport torchfrom torch.autograd import Variableimport torch.nn as nnimport torch.optim as optimimport torch.nn.functional as Fimpor

Web/HTTP 调试利器(Fiddler)_一去丶二三里的博客-程序员秘密

简述Fiddler 是一个 http 协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的 http 通讯,设置断点,查看所有的“进出”Fiddler 的数据(指 cookie、html、js、css 等文件,这些都可以让你胡乱修改的意思)。Fiddler 要比其他的网络调试器要更加简单,因为它不仅仅暴露 http 通讯还提供了一个用户友好的格式。简述介绍工作原理同类产品

分享: 云风开发笔记 (5) : 场景服务及避免读写锁_a13393665983的博客-程序员秘密

分享: 云风开发笔记 (5) : 场景服务及避免读写锁 云风开发笔记 (5) : 场景服务及避免读写锁 http://my.oschina.net/alex1989/blog/114262 ...

matlab引用csv文件,如何用MATLAB读取csv文件_weixin_39534100的博客-程序员秘密

如何使用Matlab读取csv文件在Matlab中,有专门读取csv文件的函数:csvread()。在Matlab的帮助文档中,有对这个函数的详细解释。csvread()函数有三种使用方法:1、M = csvread('filename')2、M = csvread('filename', row, col)3、M = csvread('filename', row, col, range)第一种...

HTML5期末大作业:X米网站设计——小米商城手机(10页) HTML+CSS+JavaScript 学生DW网页设计作业成品 学生dreamweaver网页设计作业成品_web领域优质创作者-网页设计的博客-程序员秘密

HTML5期末大作业:X米网站设计——小米商城手机(10页) HTML+CSS+JavaScript 学生DW网页设计作业成品 学生dreamweaver网页设计作业成品常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 明星、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 军事、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他 等网页设计题目, A+水平作业, 可满足大学生

linux用户管理及文件权限_weixin_30856965的博客-程序员秘密

一、Linux 用户管理Linux 是一个可以实现多用户登陆的操作系统,多人可以同时登陆同一台主机,他们共享一些主机的资源,但他们也分别有自己的用户空间,用于存放各自的文件。但实际上他们的文件都是放在同一个物理磁盘上的甚至同一个逻辑分区或者目录里,但是由于 Linux 的 用户管理 和 权限机制 ,不同用户不可以轻易地查看、修改彼此的文件。1.查看用户$ who am i 或者$ ...

随便推点

吉布斯采样——原理及matlab实现_吉布斯采样例子_风翼冰舟的博客-程序员秘密

原文来自:https://victorfang.wordpress.com/2014/04/29/mcmc-the-gibbs-sampler-simple-example-w-matlab-code/【注】评论区有同学指出译文理论编码有误,请参考更官方的文献,个人当时仅验证过红色字体部分理论与维基百科中二位随机变量吉布斯采样的结果是否对应,其余部分有意见希望可以详细指出,大家互相交流。M...

海思MPP业务MMZ内存优化介绍_hi_LeTian的博客-程序员秘密

海思MPP业务MMZ内存优化介绍概述       完全是本着内存吃紧的情况下的一些优化点,都是在文档有介绍的,自己多调试下就出来了,好不好用,还请自己评估,这里只是给出一些点的介绍。本着有坑也不填的原则,这里只做交流使用,后果自负。OS内存和MMZ海思的安防平台芯片的内存主要划分两部分来管理,一部分是系统使用的OS内存,一部分是称为MMZ的内存,具体这两部分如何配置和使用的,文档中

TCP 流量控制和拥塞控制_SJLin96的博客-程序员秘密

参考文章(侵删):TCP协议的滑动窗口具体是怎样控制流量的? - 郭无心的回答 - 知乎TCP的拥塞控制TCP拥塞控制的问题? - 车小胖的回答 - 知乎 一. 流量控制1. 流量控制和拥塞控制两者区别流量控制:是端到端的控制,例如A通过网络给B发数据,A发送的太快导致B没法接收(B缓冲窗口过小或者处理过慢),这时候的控制就是流量控制,原理是通过滑动窗口的大小改变来实现...

matplotlib:font_manager模块FontProperties类的使用(字体属性)_mighty13的博客-程序员秘密

FontProperties类概述FontProperties类用于存储和操作字体的属性。matplotlib支持的字体属性基于W3C Cascading Style Sheet, Level 1 font specification,主要有以下6个:字体类别(family)、字体风格(style)、字体粗细(weight)、字体大小(size)、字体拉伸(stretch)和字体变体(variant)。FontProperties类签名为:class matplotlib.font_manager.F

[高通SDM450][Android9.0]CTA认证--蓝牙、WIFI申请权限_android wifi权限申请_Mr. 码农的博客-程序员秘密

文章目录开发平台基本信息问题描述解决方法开发平台基本信息芯片: SDM450版本: Android 9.0kernel: msm-4.9问题描述设备在进行入网认证的时候,实验室要求应用在使用特殊权限的时候,需要告知用户,要用户授权才能使用相应的权限;在高版本的安卓系统里,类似相机、位置这些权限都能自动申请,但是,像蓝牙、wifi的使用,是没有弹框提示用户授权的,实验室要求,蓝牙、wifi同样需要弹框提示用户授权。解决方法diff --git a/frameworks/base/core/j

推荐文章

热门文章

相关标签