Spring

About Spring

开源免费框架,轻量级,非入侵式框架。Spring就是一个轻量级的控制反转(IOC)和面向切片编程(AOP)的框架

Maven repo:Spring Web MVC + spring-jdbc(整合Mybatis)

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>

Spring两大特点

控制反转(IOC)

面向切片编程(AOP)支持事务处理

Spring

About IOC

控制反转:IOC是一种设计思想,通过描述(XML或注解)并通过第三方生产或获取对象的方式。之前对象的创建与对象的依赖关系完全在java硬编码程序中,控制权在程序;实现IOC后,控制权在第三方,实现降藕。

在Spring中实现控制反转的是IoC容器,实现方法是依赖注入DI(Dependency Injection,DI)

引用狂神的一个例子简单理解下

private UserDao userDao = null;

public UserServiceImpl(){
userDao = new UserDaoImpl();
}

在之前我们使用JavaWeb写service=>dao的时候,是通过如上的方式去实现的,项目构建大概如下

那么如果此时我的UserDao接口又了一个新的实现类暂且为UserDaoImpls,这个实现类中有新的功能实现,那么就需要到UserServiceImpl中再去构造方法加一段如下的代码:

userDao = new UserDaoImpls();

那么这时如果该项目还没发布那到无所谓,如果是已经上线的项目是不可能这样重新去修改代码的,或者如果有n个new,就要修改n处。

解决这个问题就是通过一个set方法。如下:

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

在构造方法中实例化对象的这个操作,改为利用set封装并将需要new的实现类的名称变为set方法的参数,实现用户可控的去new一个新的实现类从而添加新的功能展示到页面。

而这个思想就是控制反转(IOC)的原型,将new实现类对象的主动权交给了用户而不是程序,从本质上解决了上面的问题,也实现了降藕。

Hello Spring

Hello.java

package com.zh1z3ven.pojo;

public class Hello {
private String str; public Hello() {
} public Hello(String str) {
this.str = str;
} public String getStr() {
return str;
} public void setStr(String str) {
this.str = str;
} @Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}

Beans.xml

一个bean标签代表一个对象, id代表在Spring中这个类要实例化生成的对象的名字, class指定这个实体类

设置对象的属性值

引用Spring容器中创建的对象

<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring创建对象,Spring都称之为bean-->
<!-- 一个bean标签代表一个对象, id代表要实例化的对象的名字, class指定这个实体类-->
<bean id="hello" class="com.zh1z3ven.pojo.Hello">
<!-- 设置实体类的属性值-->
<property name="str" value="Spring"/>
</bean>
</beans>

Test.java

在Spring中也存在一个上下文,通过ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");传入xml配置文件名字来获取该xml文件的上下文对象。利用ApplicationContext#getBean()传入在xml中配置的该类的id获取该实体类对象。

public class MyTest {
public static void main(String[] args) { //获取Spring上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//从Spring中取出对象
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello); }
}

IOC创建对象的几种方式

PS:在配置文件加载的时候,通过bean标签注册的对象就已经在Spring IoC容器中初始化了。

总体来说就两种方式:

  • 无参构造

    默认使用

  • 有参构造

    1. 下标赋值

      <!--通过下标赋值-->
      <bean id="hello2" class="com.zh1z3ven.pojo.Hello">
      <constructor-arg index="0" value="Spring2"/>
      </bean>
    2. 类型复制

      <!--通过类型赋值-->
      <bean id="hello3" class="com.zh1z3ven.pojo.Hello">
      <constructor-arg type="java.lang.String" value="Spring3"/>
      </bean>
    3. 属性名赋值

      <!--属性名赋值-->
      <bean id="hello4" class="com.zh1z3ven.pojo.Hello">
      <constructor-arg name="str" value="Spring4"/>
      </bean>

Spring import settings

import标签可导入其他beans.xml配置文件,而applicationContext.xml到时可作为总bean的配置文件,而不需要导入多个xml

Dependency Injection

依赖注入(Dependency Injection,DI)

PS:一定需要pojo中实现set才可以利用bean标签注入

  1. 构造器注入

    也就是上面提到的创建对象的方式,分为无参构造和有参构造

    • 无参构造

      默认使用

    • 有参构造

      1. 下标赋值

        <!--通过下标赋值-->
        <bean id="hello2" class="com.zh1z3ven.pojo.Hello">
        <constructor-arg index="0" value="Spring2"/>
        </bean>
      2. 类型复制

        <!--通过类型赋值-->
        <bean id="hello3" class="com.zh1z3ven.pojo.Hello">
        <constructor-arg type="java.lang.String" value="Spring3"/>
        </bean>
      3. 属性名赋值

        <!--属性名赋值-->
        <bean id="hello4" class="com.zh1z3ven.pojo.Hello">
        <constructor-arg name="str" value="Spring4"/>
        </bean>
  2. set注入

    依赖:bean对象的注入依赖于Spring容器

    注入:bean对象的属性,由容器来注入

  3. 拓展注入

    Student.java

    public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String,String> card;
    private Set<String> games;
    private String wife;
    private String apache;
    private Properties info; public String getApache() {
    return apache;
    } public void setApache(String apache) {
    this.apache = apache;
    } public String[] getBooks() {
    return books;
    } public void setBooks(String[] books) {
    this.books = books;
    } public List<String> getHobbys() {
    return hobbys;
    } public void setHobbys(List<String> hobbys) {
    this.hobbys = hobbys;
    } public Map<String, String> getCard() {
    return card;
    } public void setCard(Map<String, String> card) {
    this.card = card;
    } public Set<String> getGames() {
    return games;
    } public void setGames(Set<String> games) {
    this.games = games;
    } public String getWife() {
    return wife;
    } public void setWife(String wife) {
    this.wife = wife;
    } public Properties getInfo() {
    return info;
    } public void setInfo(Properties info) {
    this.info = info;
    } public String getName() {
    return name;
    } public void setName(String name) {
    this.name = name;
    } public Address getAddress() {
    return address;
    } public void setAddress(Address address) {
    this.address = address;
    } @Override
    public String toString() {
    return "Student{" +
    "name='" + name + '\'' +
    ", address=" + address +
    ", books=" + Arrays.toString(books) +
    ", hobbys=" + hobbys +
    ", card=" + card +
    ", games=" + games +
    ", wife='" + wife + '\'' +
    ", info=" + info +
    '}';
    }
    }

    beans.xml

    <bean id="address" class="com.zh1z3ven.pojo.Address">
    <property name="address" value="beijing"/>
    </bean>
    <bean id="student1" class="com.zh1z3ven.pojo.Student">
    <!-- 普通属性值注入-->
    <property name="name" value="zh1z3ven"/> <!-- ref 引用对象注入-->
    <property name="address" ref="address"/> <!-- 数组array注入-->
    <property name="books">
    <array>
    <value>红楼梦</value>
    <value>西游记</value>
    <value>水浒传</value>
    <value>三国演义</value>
    </array>
    </property> <!-- List注入-->
    <property name="hobbys">
    <list>
    <value>听音乐</value>
    <value>看电影</value>
    <value>敲代码</value>
    <value>写文章</value>
    </list>
    </property> <!-- Map注入-->
    <property name="card">
    <map>
    <entry key="银行卡" value="1"></entry>
    <entry key="身份证" value="2"></entry>
    <entry key="学生证" value="3"></entry>
    <entry key="电话卡" value="4"></entry>
    <entry key="校园卡" value="5"></entry>
    </map>
    </property> <!-- Set注入-->
    <property name="games">
    <set>
    <value>LOL</value>
    <value>CF</value>
    <value>qq</value>
    </set>
    </property> <!-- null注入-->
    <property name="wife">
    <null></null>
    </property> <!-- 空值注入-->
    <property name="apache" value=""/> <!-- properties-->
    <property name="info">
    <props>
    <prop key="id">10</prop>
    <prop key="city">北京</prop>
    </props>
    </property>
    </bean>

P-namespcae&C-namespace

  1. p命名空间注入,可以直接注入属性值,类似于bean标签中property-name-value

    Beans.xml头部需导入

    xmlns:p="http://www.springframework.org/schema/p"
    <bean id="user1" class="com.zh1z3ven.pojo.User" p:name="zh1z3ven1" p:age="18"/>
  2. c命名空间注入,通过构造器注入,类似于construct-args(需要实现有参构造)

    xmlns:c="http://www.springframework.org/schema/c"
    <bean id="user2" class="com.zh1z3ven.pojo.User" c:name="zh1z3ven2" p:age="19"/>
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user1 = context.getBean("user1", User.class);
System.out.println(user1.getName());
System.out.println(user1.getAge()); User user2 = context.getBean("user2", User.class);
System.out.println(user2.getName());
System.out.println(user2.getAge());
}

Bean scopes

bean的作用域

singleton

默认bean为scope = singleton单例模式运行的

显示定义:<bean id="user1" class="com.zh1z3ven.pojo.User" p:name="zh1z3ven1" p:age="18" scope="singleton"/>

单例模式,共享一个对象,比如如下例子,getBean指向的是同一个bean,那么在Spring IoC容器中仅仅会生成一个"user2"对象保存在内存中,当调用ApplicationContext.getBean("user2")时返回该对象

<bean id="user2" class="com.zh1z3ven.pojo.User" c:name="zh1z3ven2" c:age="19"/>
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user1 = context.getBean("user2", User.class);
User user2 = context.getBean("user2", User.class);
System.out.println(user1==user2);
}

prototype

原型模式prototype与singleton不同,每次上下文去getBean()时都会在Spring IoC容器内创建一次该对象

还是拿上面的测试代码,可以发现已经不是同一个对象了,有点类似于多态

public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user1 = context.getBean("user2", User.class);
User user2 = context.getBean("user2", User.class);
System.out.println(user1==user2);
}

而其余的生命周期在Web中才会遇到。

Bean的自动装配

  • 在xml显示配置bean
  • 在java代码中配置bean
  • 隐式自动装配bean【autowire】

byName autowire

会在容器上下文中自动查找,和自己对象set方法后面的值对应的beanid。也就是这里会去上下文中寻找有无"cat"这个beanid,有则自动装配,如果并没有匹配上,比如此时beanid被修改为了"cat123" 就会跑出异常。

byType autowire

会在容器上下文中寻找该类型与属性值所对应的类型相同的bean,基于bean中的class(需要在上下文中所有类型各自只出现一次)

<bean id="people" class="com.zh1z3ven.pojo.People" autowire="byType">
<property name="name" value="zh1z3ven"/>
</bean>

小结

  • byname需要保证所有bean的id唯一,且这个bean的id的值要和需要自动装配依赖注入的set方法的值一致。
  • bytype需要保证所有bean的class唯一,且这个bean的class的值需要和set方法的值的类型一致。

注解实现自动装配

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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> </beans>

@Autowired

默认使用byname方式去自动装配,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。

在使用@Autowired时,首先在容器中查询对应类型的bean(bytype)

如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据

如果查询的结果不止一个,那么@Autowired会根据名称来查找。(byname)

如果查询的结果为空,那么会抛出异常。解决方法时,使用@Autowried(required=false)

public class People {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
private String name;

@Qualifier

如果存在多个类型且该类型有多个不同名字的对象,那么只用@Autowired会找不到该对象,可以配合@Qualifier(value="")来指定一个装配的值。

@Autowired
@Qualifier(value="dog222")

@Resource

java自带的一个注解,和@Autowired,@Qualifier组合用法和效果基本是一样

javax.annotation.Resource
@Resource //不指定名称自动装配
@Resource(name="") //指定名称自动装配

使用注解开发

bean在xml里注册,属性值通过注解注入

@component

泛指各种组件,把普通pojo实例化到spring容器中,相当于配置文件中的bean,将该类在配置文件下注册到Spring容器中装配bean。类似的还有:

1、@controller 控制器(注入服务)

用于标注控制层,相当于struts中的action层

2、@service 服务(注入dao)

用于标注服务层,主要用来进行业务的逻辑处理

3、@repository(实现dao访问)

用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件.

@Scope

生命周期,用法:在目标类上面声明

@Scope("singleton")

@Configuration

用于声明这是一个配置类

@Bean

相当于在配置文件中注册bean

方法名为之前的id属性

方法返回值为之前的class属性

@Import

导入其他配置类,等价于

<import resource="beans.xml"/>

使用方法

@Import(Config.class)

示例代码

pojo

//相当于在bean中注册,相当于在Spring IoC容器new一个对象
@Component
public class User {
@Value("CoLoo")
public String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}

config

@Configuration
@ComponentScan("com.zh1z3ven.pojo")
public class AppConfig {
@Bean
public User getUser(){
return new User();
}
}

test

public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
User user = context.getBean("user", User.class);
System.out.println(user.getName());
}
}

Java之Spring基础与IoC的更多相关文章

  1. Spring基础之IOC

    一.ioc能解决什么问题 1.Spring是什么 spring是以ioc和aop为核心,能整合第三方框架和类库的企业级应用开源框架. 2.程序的耦合问题 例子:Driver类必须存在,编译才通过,Jd ...

  2. Spring基础——在 IOC 容器中 Bean 之间的关系

    一.在 Spring IOC 容器中 Bean 之间存在继承和依赖关系. 需要注意的是,这个继承和依赖指的是 bean 的配置之间的关系,而不是指实际意义上类与类之间的继承与依赖,它们不是一个概念. ...

  3. 01—Spring基础配置IOC

  4. 第65节:Java后端的学习之Spring基础

    Java后端的学习之Spring基础 如果要学习spring,那么什么是框架,spring又是什么呢?学习spring中的ioc和bean,以及aop,IOC,Bean,AOP,(配置,注解,api) ...

  5. Spring笔记:IOC基础

    Spring笔记:IOC基础 引入IOC 在Java基础中,我们往往使用常见关键字来完成服务对象的创建.举个例子我们有很多U盘,有金士顿的(KingstonUSBDisk)的.闪迪的(SanUSBDi ...

  6. (转)java之Spring(IOC)注解装配Bean详解

    java之Spring(IOC)注解装配Bean详解   在这里我们要详细说明一下利用Annotation-注解来装配Bean. 因为如果你学会了注解,你就再也不愿意去手动配置xml文件了,下面就看看 ...

  7. JAVA模拟Spring实现IoC过程(附源码)

    前言:本人大四学生,第一次写博客,如果有写得不好的地方,请大家多多指正 一.IoC(Inversion of Control)反转控制 传统开发都是需要对象就new,但这样做有几个问题: 效率低下,创 ...

  8. 【已转移】【Java架构:基础技术】一篇文章搞掂:Spring

    本文篇幅较长,建议合理利用右上角目录进行查看(如果没有目录请刷新). 本文是对<SPRING实战第4版>的总结,大家也可以去仔细研读该书 [------------------------ ...

  9. Spring基础知识

    Spring基础知识 利用spring完成松耦合 接口 public interface IOutputGenerator { public void generateOutput(); } 实现类 ...

随机推荐

  1. 《快来为你的 .NET 应用加个监控吧!》更新版本啦

    目录 导读 三种方式处理监控数据 主动推送 ASP.NET Core 自定义URL .NET diagnostics 自定义监控指标 导读 CZGL.ProcessMetrics 是一个 Metric ...

  2. 「CF446C」 DZY Loves Fibonacci Numbers

    「CF446C」 DZY Loves Fibonacci Numbers 这里提供一种优美的根号分治做法. 首先,我们考虑一种不太一样的暴力.对于一个区间加斐波那契数的操作 \([a,b]\),以及一 ...

  3. Python使用笔记005-文件操作(二)

    1.1 打开文件模式 # r r+ r+读是没问题的,写的话,会覆盖原来的内容,文件不存在时会报错# w w+ w+用来新的文件没问题,旧的文件会覆盖原来的内容# a a+ a+写是追加,读不到是因为 ...

  4. stream之map的用法

    一.Stream管道流map的基础用法 最简单的需求:将集合中的每一个字符串,全部转换成大写! List<String> alpha = Arrays.asList("Monke ...

  5. shell脚本(5)-shell变量

    一.变量介绍 将一些数据需要临时存放在内存中,以待后续使用时快速读出. 二.变量分类 1.本地变量: 用户私有变量,只有本用户可以使用,保存在家目录下的.bash_profile..bashrc文件中 ...

  6. virtualbox结合nat和host-only设置固定ip的环境

    需求 平时在做一些实验或学习的时候,比如rocketmq.kafaka.zookeeper等,需要在虚拟机上创建几个虚拟机组成集群来做实验:一般有两个要求: 虚拟机能访问网络,需要下载安装东西 虚拟机 ...

  7. 9Java基础总结

    1.psvm定义的意义 public:保证了方法的访问权限 static:保证在类未被实例化的时候就能调用(加载的时机) void:不需要返回值 main:约定俗成的名字 String[] args: ...

  8. Flask 之db 配置坑

    文件 .flaskenv中 DATABASE_URI = 'mysql://username:password@server/db' flask db init 报错 ImportError: No ...

  9. Django关闭html转义

    我们在views定义的html语句传递到html文件会按照原样式输出,并把我们定义的html标签页输出了,这是因为django模板默认帮我们开起了html转义功能 {{ lp}} <hr> ...

  10. 关于maven打包与jdk版本的一些关系

    最近让不同JAVA版本的容器maven打包折腾的不行,终于理出了一点头绪.在这里记录下备忘. 1. Maven与jdk版本的关系 先明确一个概念,关高版本JDK运行maven,是可以打出低版本的JAV ...