1 Spring概念

Spring是轻量级的开源JavaEE框架。可以解决企业开发的复杂性。

Spring有两个核心部分:IOC和Aop

①IOC控制反转:把创建对象过程交给Spring管理

②Aop:面向切面,不修改源代码的情况下进行功能增强

Spring5相关jar包:spring-beans-5.2.6.RELEASE.jar

spring-context-5.2.6.RELEASE.jar

spring-core-5.2.6.RELEASE.jar

spring-expression-5.2.6.RELEASE.jar

通过Spring配置文件创建对象

    @Test
public void test() {
// 加载Spring配置文件
ApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
// 获取配置创建的对象
user u = (user) context.getBean("user");
u.add();
}

ClassPathXmlApplicationContext对应src下的文件

FileSystemXmlApplicationContext对应磁盘路径

bean1.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.hikaru.spring5.user"></bean>
</beans>

2 IOC容器

控制反转:把对象创建和对象之间的调用过程,交给Spring进行管理。

IOC底层原理

IOC过程: xml解析+工厂模式+反射

①配置xml文件,配置创建的对

<bean id="user" class="com.hikaru.spring5.user"></bean>

②创建工厂类

xml解析后通过反射创建对象,进一步降低耦合度。

public class userFactory {
public static user getUser() {
String classValue = classuser;
Class clazz = Class.forName(classValue); return clazz.newInstance();
}
}

比如user类路径需要修改,那么只需要修改配置文件

IOC接口

Spring提供IOC容器的两种方式(两个接口):

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

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

②ApplicationContext:BeanFactory接口的子接口,提供了更多更强大的功能,面向开发人员使用

加载配置文件的时候就创建对象

web项目一般选择第二种方式,当服务器启动的时候就完成这些耗时的工作

IOC操作Bean管理

两种实现方式:

①基于配置文件方式

创建对象

<bean id="user" class="com.hikaru.spring5.user"></bean>
bean标签的常用属性
id 标签的唯一标识,不是实例名
class 安全路径(包类路径)
name 与id类似,但是name可以用特殊字符

这种方式创建对象时,默认执行的是无参构造器完成对象创建,如果类中只有有参数构造器没有无参构造器则会报错

DI依赖注入(属性):

①使用set方法注入

<property name="userName" value="刘"></property>

②使用有参数构造器注入

<constructor-arg name="userName" value="ryuu"></constructor-arg>
<constructor-arg index="1" value="9512891"></constructor-arg>

可以通过属性名、属性在构造器的索引号注入依赖

③使用p名称空间注入

首先添加p名称空间在配置文件中

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<bean id="user" class="com.hikaru.spring5.user" p:userName="liu" p:pwd="pwd123">
</bean>
※ xml注入其它类型属性
  1. 字面量

(1)空值

        <property name="userName">
<null></null>
</property>
<property name="pwd">
<null></null>
</property>

(2)包含特殊字符 <![CDATA[...]>

        <property name="userName">
<value><![CDATA[<><><>]]]></value>
</property>
  1. 注入外部bean
    <bean id="service" class="com.hikaru.spring5.testDemo.service">
<property name="d" ref="daoImpl"></property>
</bean>
<bean id="daoImpl" class="com.hikaru.spring5.testDemo.daoImpl">
</bean>

必须对外部bean进行声明

  1. 注入内部bean
    <bean id="emp" class="com.hikaru.spring5.testDemo.emp">
<property name="name" value="luffer"></property> <property name="d">
<bean id="d" class="com.hikaru.spring5.testDemo.dept">
<property name="deptName" value="jishubu"></property>
</bean>
</property>
</bean>

这里不能使用单元测试,单元测试只允许使用一个构造器

4.级联赋值

一种是外部bean注入属性后再注入bean

另一种内部bean注入属性

5.注入集合属性

数组:

        <property name="courses">
<array>
<value>Java</value>
<value>数据库</value>
</array>
</property>

list:

        <property name="list">
<list>
<value>张三</value>
<value>法外狂徒</value>
</list>
</property>

set:

        <property name="set">
<set>
<value>MySQL</value>
<value>Redis</value>
</set>
</property>

map:

        <property name="map">
<map>
<entry key="Java" value="java">
</entry> <entry key="PHP" value="php">
</entry>
</map>
</property>
工厂Bean
public class myBean implements FactoryBean<Course>{

    @Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("C#");
return course;
} @Override
public Class<?> getObjectType() {
return null;
} @Override
public boolean isSingleton() {
return false;
}
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Course c= (Course) context.getBean("myBean", Course.class);
System.out.println(c);
}
}

工厂Bean区别于普通Bean,xml配置文件定义的Bean类型与返回类型可以不同

Bean的作用域

1 单例模式与多例模式

    <bean id="myBean" class="myBean" scope="prototype">
</bean>
    <bean id="myBean" class="myBean" scope="singleton">
</bean>

Spring中默认情况为单例模式,每次返回的实例都是一个实例

myBean@3d921e20
myBean@36b4cef0

上为多例模式的实例地址

Bean的生命周期

(1)通过构造器创建bean实例(无参数构造,或通过p进行有参构造)

(2)为bean的 属性 设置值和其它对象的引用(set方法)

(3)调用bean的初始化方法(需要进行配置初始化的方法)

(4)获取到bean对象进行使用

(5)当容器关闭时,调用bean的销毁方法(需要进行配置销毁的方法)

演示Bean的生命周期
public class Order {
private String oname; public Order() {
System.out.println("step1");
} public String getOname() {
return oname;
} public void setOname(String oname) {
this.oname = oname;
System.out.println("step2");
} public void initMethod() {
System.out.println("step3:init Bean");
} public void destroyMethod() {
System.out.println("step5:destroy Eean");
} @Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Order order = context.getBean("Order", Order.class);
System.out.println("step4:get bean"); ((ClassPathXmlApplicationContext) context).close();
}
}

ApplicationContext作为接口没有close方法,但是其实现类ClassPathXmlApplicationContext 有,所以这里需要进行强转或者开始使用ClassPathXmlApplicationContext生声明

XML

    <bean id="Order" class="Order" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="order1"></property>
</bean>
step1
step1
step2
step3:init Bean
step4:get bean
step5:destroy Eean
bean的后置处理器

在声明周期的第三步之前和之后:

(1)通过构造器创建bean实例(无参数构造,或通过p进行有参构造)

(2)为bean的 属性 设置值和其它对象的引用(set方法)

把bean实例传递给后置处理器的方法

(3)调用bean的初始化方法(需要进行配置初始化的方法)

把bean实例传递给后置处理器的方法

(4)获取到bean对象进行使用

(5)当容器关闭时,调用bean的销毁方法(需要进行配置销毁的方法)

public class postBean implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before init");
return bean;
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("after init");
return bean;
}
}

实现BeanPostProcessor接口的bean会被当做后置处理器

    <bean id="Order" class="Order" init-method="initMethod" destroy-method="destroyMethod">
<property name="oname" value="order1"></property>
</bean> <bean class="postBean"></bean>

后置bean会对xml中的所有bean生效

输出结果:

step1
step1
step2
before init
step3:init Bean
after init
step4:get bean
step5:destroy Eean
自动装配

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

根据属性类型装配

    <bean id="Emp" class="Emp" autowire="byType"></bean>
<bean class="Dept">
<property name="dName" value="develop"></property>
</bean>

这种方式的外部bean不能声明为相同的类型

根据属性名称装配

        <bean id="Emp" class="Emp" autowire="byName"></bean>
<bean id="dept" class="Dept">
<property name="dName" value="develop"></property>
</bean>

这种方式要求外部bean名称与bean的属性名相同

引入外部属性文件

首先添加context约束声明

xmlns:context="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 http://www.springframework.org/schema/context/spring-context.xsd">
    <context:property-placeholder location="classpath:JDBC.properties"/>

    <bean id="Druid" class="com.alibaba.druid.pool.DruidDataSource" >
<property name="driverClassName" value="${prop.driverClassName}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.username}"></property>
<property name="password" value="${prop.password}"></property>
</bean>

随后通过读取外部properties文件的方式建立德鲁伊数据库连接池

这里的外部文件获取必须使用${prop.}的形式

②基于注解方式

注解是代码的特殊标记,格式:@注解名称(属性名称:属性值,属性名称:属性值...),注解可以作用在类、方法、属性上。注解的目的是简化xml配置。

Spring针对Bean管理中创建对象提供的注解:

(1) @Componet

(2) @Service

(3) @Controller

(4) @Repository

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

步骤:

(1)引入jar包:spring-aop-5.2.6.RELEASE.jar

(2)配置文件中添加context约束,并在配置文件中进行组件扫描(告诉Spring哪个包、类中存在注解)

xmlns:context="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 http://www.springframework.org/schema/context/spring-context.xsd"
>
<context:component-scan base-package="service"></context:component-scan>

多个包可以用,隔开 或者使用上层包名

(3)在Bean类上添加注解

@Component
public class UserService {
public void add() {
System.out.println("service add...");
}

或者使用@Component(value="userService"),value值对应xml配置bean的id写法,value省略时默认为第一个字母小写的类名

组件过滤扫描
<context:component-scan base-package="service" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>

不使用默认扫描,只扫描注解为Component的Bean

<context:component-scan base-package="service" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>

使用默认扫描但不扫描注解为Component的Bean

注解实现属性注入:只需要在配置文件设置组件扫描,其他均通过类注解实现

①Autowired:根据属性类型自动装配

第一步 在service和dao上添加创建对象注解创建对象

第二步 在service类中的dao属性上添加Autowired注解注入dao属性

注解封装了属性的set方法,不需要再次创建

@Component
public class UserService {
@Autowired
private UserDao userDao; public void add() {
userDao.add();
}

②Qualifier:根据属性名称自动装配,需要配合Autowired使用

@Component
public class UserService {
@Autowired
@Qualifier(value = "userDaoImpl")
private UserDao userDao; public void add() {
userDao.add();
}

比如UserDao有多个实现类,所以需要注解指名是哪一个,这里的userDaoImpl是实现类创建注解默认生成的首字母小写的类名

③Resource:

    @Resource(name = "userDaoImpl")
private UserDao userDao;

等价于@Autowired

           @Qualifier(value = "userDaoImpl")

④Value:

    @Value("123")
private String name;

同样不需要set方法

完全注解开发

配置注解另类为配置类,替代xml配置文件

设置自动扫描组件注解

@Configuration
@ComponentScan(basePackages = {"service", "dao"})
public class SpringConfig { }

加载配置类:AnnotationConfigApplicationContext

        ApplicationContext context =
new AnnotationConfigApplicationContext(SpringConfig.class);

【Spring5】IOC的更多相关文章

  1. 【调侃】IOC前世今生

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  2. 【调侃】IOC前世今生(转)

    前些天,参与了公司内部小组的一次技术交流,主要是针对<IOC与AOP>,本着学而时习之的态度及积极分享的精神,我就结合一个小故事来初浅地剖析一下我眼中的“IOC前世今生”,以方便初学者能更 ...

  3. 【Spring】 IOC Base

    一.关于容器 1. ApplicationContext和BeanFactory 2. 配置文件 XML方式 Java-configuration 方式 @Configuration 3. 初始化容器 ...

  4. 【Spring】IOC容器注解汇总,你想要的都在这儿了!!

    写在前面 之前,我们在[Spring]专题中更新了不少关于Spring注解相关的文章,有些小伙伴反馈说,看历史文章的话比较零散,经常会忘记自己看到哪一篇了.当打开一篇新文章时,总感觉自己似乎是看到过了 ...

  5. 【Spring】IoC容器 - 依赖查找

    前言 上一篇文章已经学习了[IoC的主要实现策略]有2种: 1.依赖查找 2.依赖注入 这里稍加详细的介绍一下依赖查找 1.依赖查找的方式 依赖查找的方式可以以多种维度来划分: 1.按名称/类型/注解 ...

  6. 【Spring】IoC容器 - Spring Bean作用域Scope(含SpringCloud中的RefreshScope )

    前言 上一章学习了[依赖来源],本章主要讨论SpringBean的作用域,我们这里讨论的Bean的作用域,很大程度都是默认只讨论依赖来源为[Spring BeanDefinition]的作用域,因为在 ...

  7. 【Spring】IoC容器 - 依赖来源

    前言 上一篇文章已经学习了[依赖注入]相关的知识,这里详细的介绍一下[依赖来源]. 依赖来源 我们把依赖来源分为依赖查找的来源和依赖注入的来源分别讨论. 依赖查找的来源 1. Spring BeanD ...

  8. 【Spring】IoC容器 - 依赖注入

    前言 上一篇文章已经学习了[依赖查找]相关的知识,这里详细的介绍一下[依赖注入]. 依赖注入 - 分类 因为自己是基于小马哥的脉络来学习,并且很认可小马哥梳理的分类方式,下面按照小马哥思想为[依赖注入 ...

  9. 【转】IoC/DIP其实是一种管理思想

    原文转自:http://blogread.cn/it/article/6487?f=wb 关于IoC的的概念提出来已经很多年了,其被用于一种面象对像的设计.我在这里再简单的回顾一下这个概念.我先谈技术 ...

  10. 【Spring】IOC

    浅谈IOC IOC的理论背景 图1:传统系统中,对象之间相互引用的一幅图,在采用面向对象方法设计的软件系统中,它的底层的实现都是由n个对象所组成的,所有的对象通彼此之间的合作最终实现系统的业务逻辑,如 ...

随机推荐

  1. day28_常用模块——hashlib,logging模块

    hashlib(摘要算法) Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等. 什么是摘要算法呢?摘要算法又称哈希算法.散列算法.它通过一个函数,把任意长度的数据转换为一个长度 ...

  2. dbeaver,执行SQL时,空行导致SQL执行报错" ERROR: syntax error at or near "case"Position: 1"

    dbeaver,执行SQL时,空行导致SQL执行报错" ERROR: syntax error at or near "case"Position: 1" 解决 ...

  3. django_模型层及ORM介绍

    一.模型层介绍 1.作用:负责跟数据库之间进行通信. 2.django通过驱动mysqlclient与mysql数据库进行通信,所以需要先安装.版本需要是1.3.13以上. 如果直接安装报错,可以直接 ...

  4. 【Unity】利用C#反射打印类的字段信息

    最近在用protobuf-net序列化功能生成.bytes配置文件时,遇到了需要把.bytes配置文件再另外转成Lua配置文件(Lua配置表内容举例)的需求.Lua配置文件需要记录配置类的各个字段名和 ...

  5. C# 循环给多个连续编号的控件赋值

    C# 循环给多个连续编号的控件赋值 我们经常在 winform 界面上用很多文本框用来显示一组数据,文本框前面有Label标识.我们得到的数据也经常是一个list 或者数组的形式的.需要给这些文本框赋 ...

  6. C语言中~与!的区别

    ! 是逻辑非or否定 ​ 凡是a的值不为0的,!a 就等于0: ​ 如果a的值为0,则 !a 的值为1 而~这个是 按位取反 比如 int a=2 ; 用二进制表示为00 00 00 10; 则 !a ...

  7. [复现]陇原战"疫"2021网络安全大赛-PWN

    bbbaby 控制__stack_chk_fail,栈溢出 from pwn import * context.os = 'linux' context.log_level = "debug ...

  8. STM32的USART的DMA不定长度收发代码

    /* * 函数名:USART1_DMA_Config * 描述  :串口1的DMA 的初始化配置 * 输入  :无 * 输出  : 无 * 调用  :在USART1_INIT()中被调用 */ voi ...

  9. 如何让Macbook Touch Bar 一直显示F1~F12

    原始状态 修改过程 系统偏好设置 > 键盘 将Touch Bar Shous 修改为F1, F2 ,etc. 结果

  10. ClassLoader 双亲委派

    一个程序有一个默认的appClassLoader.类不是由被调用者也不是被自身加载的,正常情况下是被默认的AppClassLoader加载的. System.out.println(test3.cla ...