自学——spring笔记(一)

1、主要的概念

1.1、介绍spring

它是一个分层的,轻量级的,一站式的 Java开发框架。为Java应用开发提供基础框架的支持。可以让开发者更专注与业务开发。最根本的使命是解决企业级应用开发的复杂性,即简化Java开发

spring的官网:https://spring.io

1.2、spring的特点

1.2.1、轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。

1.2.2、控制反转(IOC)——Spring通过一种称作控制反转()的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。它的底层设计模式采用了工厂模式,所有的 Bean 都需要注册到Bean工厂中,将其初始化和生命周期的监控交由工厂实现管理。程序员只需要按照规定的格式进行Bean开发,然后利用XML文件进行bean 的定义和参数配置,其他的动态生成和监控就不需要调用者完成,而是统一交给了平台进行管理。 [4]  控制反转是软件设计大师 Martin Fowler在 2004 年发表的”Inversion of Control Containers and the Dependency Injection pattern”提出的。这篇文章系统阐述了控制反转的思想,提出了控制反转有依赖查找和依赖注入实现方式。控制反转意味着在系统开发过程中,设计的类将交由容器去控制,而不是在类的内部去控制,类与类之间的关系将交由容器处理,一个类在需要调用另一个类时,只要调用另一个类在容器中注册的名字就可以得到这个类的实例,与传统的编程方式有了很大的不同,“不用你找,我来提供给你”,这就是控制反转的含义 [5]  。

面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。

所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。

2、IOC控制反转

2.1、问题引入

对于我们之前学习Java_Web的时候,遇到了一个问题:

 对于Service业务层调用Dao数据层的方法的时候,我们需要new 数据层的对象,所以如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署,这样子耦合度太高,不好!如何解决这个问题?

2.2、IOC的介绍

对于上面的问题,解决的方法就是使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象,这种实现思就是Spring的一个核心概念,此思想称为控制反转IOC

  • Spring技术对IOC思想进行了实现

  • Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"

  • IOC思想中的外部指的就是Spring的IOC容器

  • IOC容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象

  • 被创建或被管理的对象在IOC容器中统称为Bean

  • IOC容器中放的就是一个个的Bean对象

2.3、Bean的基础配置

id、name、scope与class:

<bean id="xxx" name="xxx" class="xxx" scope="xxx"/>

id : bean的id,使用容器可以利用id找到对应的bean,在一个容器中id是唯一的。
class : bean的类型,即配置的bean的实现类路径 (必须写实现类,不能写到接口,因为接口是没办法创建对象的)

name: bean的别名,可定义多个别名,能用(,)(;)(空格)分开

scope:范围,可选范围为:singleton:单例(默认)和prototype(非单例)

IOC实例(仅调用Dao层作为案例)

package stukk.Dao;
public interface UserDao {
    void deleteById(int id);
}

(Dao层的代码)

package stukk.Dao.Impl;

import stukk.Dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void deleteById(int id) {
        System.out.println("第"+id+"个已被删除");
    }
}

(实现类)

<?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-->

    <bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl"/>

</beans>

(配置文件)

package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
public class App{
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao)context.getBean("userDao");
        userDao.deleteById(2);
    }
}

(最后在App类中从容器中获取对象进行方法调用,这个过程就不需要new来创造对象了!)

但是在代码中,我们需要把dao对象交给service,也就是说要绑定service和dao对象之间的关系,这又怎么做呢???接下来就是对象之间的关系绑定的方法

3、bean三种实例化方式

3.1、构造方法实例化:

bean本质上就是对象,对象在new的时候会使用构造方法完成,那创建bean也是使用构造方法完成的。如下例:

package stukk.Dao.Impl;

import stukk.Dao.UserDao;

public class UserDaoImpl implements UserDao {
    public UserDaoImpl(){
        System.out.println("由构造方法创建");
    }
    public void deleteById(int id) {
        System.out.println("第"+id+"个已被删除");
    }
}

在实现类中的构造方法输出,结果运行成功,也会输出。说明内部走的依然是构造函数,能访问到类中的私有构造方法,显而易见Spring底层用的是反射。

 3.2、静态工厂方式实例化

package stukk.Factory;

import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;

public class UserDaoFactory {

    public static UserDao getUserDao(){
        System.out.println("静态工厂方式创建");
        return new UserDaoImpl();
    }
}

(工厂类)

    <bean id="userDao" class="stukk.Factory.UserDaoFactory" factory-method="getUserDao"></bean>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class App{
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao)context.getBean("userDao");
        userDao.deleteById(100);
    }
}

其中,class:工厂类的类全名,factory-mehod:具体工厂类中创建对象的方法名

3.3、实例工厂实例化

package stukk.Factory;

import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;

public class UserDaoFactory {

    public UserDao getUserDao(){
        System.out.println("实例工厂实例化bean");
        return new UserDaoImpl();
    }
}

创建工厂类的bean

    <bean id="userFactory" class="stukk.Factory.UserDaoFactory"/>
    <bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"/>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class App{
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao)context.getBean("userDao");
        userDao.deleteById(100);
    }
}

 配置的过程还是比较复杂,所以Spring为了简化这种配置方式就提供了一种叫FactoryBean的方式来简化开发。将实现类继承FactoryBean即可

package stukk.Factory;

import org.springframework.beans.factory.FactoryBean;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;

public class UserFactoryBean implements FactoryBean {

    public Object getObject() throws Exception {
        System.out.println("实例化工厂实例化");
        return new UserDaoImpl();
    }

    public Class<?> getObjectType() {
        return UserDao.class;
    }
}
    <bean id="userDao" class="stukk.Factory.UserFactoryBean"/>

其他配置不变,运行即可得出。

范围默认是单例,那如果想改成单例具体如何实现?只需要将isSingleton()方法进行重写,修改返回为false,即可。

3.4、总结

Spring的IOC实例化对象的三种方式分别是:

  • 构造方法(常用)

  • 静态工厂(了解)

  • 实例工厂(了解)

    • FactoryBean(实用)

4、bean的生命周期

  • 首先理解下什么是生命周期?

    • 从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期。

  • bean生命周期是什么?

    • bean对象从创建到销毁的整体过程。

  • bean生命周期控制是什么?

    • 在bean创建后到销毁前做一些事情。

(1)关于Spring中对bean生命周期控制提供了两种方式:

  • 在配置文件中的bean标签中添加init-methoddestroy-method属性

  • 类实现InitializingBeanDisposableBean接口,这种方式了解下即可。

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
package stukk.Dao.Impl;

import stukk.Dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void deleteById(int id) {
        System.out.println("第"+id+"个已被删除");
    }
    public void init(){
        System.out.println("init。。。");
    }
    public void destory(){
        System.out.println("destroy......");
    }
}
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class App{
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao)context.getBean("userDao");
        userDao.deleteById(100);
        context.close();
    }
}

(2)对于bean的生命周期控制在bean的整个生命周期中所处的位置如下:

  • 初始化容器

    • 1.创建对象(内存分配)

    • 2.执行构造方法

    • 3.执行属性注入(set操作)

    • ==4.执行bean初始化方法==

  • 使用bean

    • 1.执行业务操作

  • 关闭/销毁容器

    • ==1.执行bean销毁方法==

(3)关闭容器的两种方式:

  • ConfigurableApplicationContext是ApplicationContext的子类

    • close()方法

    • registerShutdownHook()方法

5、DI(Dependency Injection)依赖注入

我们知道Service层的方法依赖Dao层的对象来运行,在之前业务层要用数据层的类对象,以前是自己new的,现在自己不new了,靠IOC容器来给注入进来,这种思想就是依赖注入(DI)

5.1、setter注入

案例:

1.删除业务层中使用new的方式创建的dao对象

2.在业务层提供UserDao的setter方法

3.在配置文件中添加依赖注入的配置

4.运行程序调用方法

package stukk.Service;
public interface UserService {
    void deleteById(int id);
}

(UserService类)

package stukk.Service.Impl;

import stukk.Dao.BookDao;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class UserServiceImpl implements UserService {
    UserDao userDao;
//    = new UserDaoImpl();  把他去掉了
    public void deleteById(int id) {
        userDao.deleteById(id);
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }//注意加入set方法哦!
}

(UserService实现类)

<?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-->

    <bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl"/>
    <bean id="userService" class="stukk.Service.Impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>

</beans>

(配置文件,为bean设置依赖注入 property标签表示配置当前bean的属性,name属性表示配置哪一个具体的属性,ref属性表示参照哪一个bean)

package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class App{
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService)context.getBean("userService");
        userService.deleteById(100);
    }
}

(App类运行程序,结果OK)

5.2、注入简单数据类型

步骤:

1.在BookDaoImpl类中声明对应的简单数据类型的属性

2.为这些属性提供对应的setter方法

3.在applicationContext.xml中配置

package stukk.Dao.Impl;

import stukk.Dao.UserDao;

import java.math.BigInteger;

public class UserDaoImpl implements UserDao {
    private String username;
    private BigInteger password;
    public void deleteById(int id) {
        System.out.println("第"+id+"个已被删除");
        System.out.println(username+":"+password);
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(BigInteger password) {
        this.password = password;
    }
}
    <bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl">
        <property name="username" value="stu_kk"/>
        <property name="password" value="123456789"/>
    </bean>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class App{
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao)context.getBean("userDao");
        userDao.deleteById(100);
    }
}

5.3、构造器注入

在UserService实现类中利用构造方法进行注入

标签<constructor-arg>中

  • name属性对应的值为构造函数中方法形参的参数名,必须要保持一致。

  • ref属性指向的是spring的IOC容器中其他bean对象。

package stukk.Service.Impl;

import stukk.Dao.BookDao;
import stukk.Dao.Impl.UserDaoImpl;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class UserServiceImpl implements UserService {
    UserDao userDao;
    public UserServiceImpl(UserDao userDao){
        this.userDao = userDao;
    }
    public void deleteById(int id) {
        userDao.deleteById(id);
    }
}
<?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="userDao" class="stukk.Dao.Impl.UserDaoImpl">
        <property name="username" value="stu_kk"/>
        <property name="password" value="123456789"/>
    </bean>

    <bean id="userService" class="stukk.Service.Impl.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>

</beans>
package stukk;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import stukk.Dao.UserDao;
import stukk.Service.UserService;

public class App{
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService)context.getBean("userService");
        userService.deleteById(10);
    }
}

5.4、自动配置

前面的配置文件太麻烦了,所以有自动配置这种简便的方法

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

    <bean id="userService" class="stukk.Service.Impl.UserServiceImpl" autowire="byType"/>

结果也是可以,和前面一样的结果

5.3、集合注入

常见的集合类型有哪些?

  • 数组

  • List

  • Set

  • Map

  • Properties

针对不同的集合类型,进行注入!

package stukk.Dao.Impl;

import stukk.Dao.UserDao;

import java.math.BigInteger;
import java.util.*;
public class UserDaoImpl implements UserDao {
    private int[] array;

    private List<String> list;

    private Set<String> set;

    private Map<String,String> map;

    private Properties properties;

    public void deleteById(int id) {
        System.out.println("book dao save ...");

        System.out.println("遍历数组:" + Arrays.toString(array));

        System.out.println("遍历List" + list);

        System.out.println("遍历Set" + set);

        System.out.println("遍历Map" + map);

        System.out.println("遍历Properties" + properties);
    }

    public void setArray(int[] array) {
        this.array = array;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setMap(Map<String, String> map) {
        this.map = map;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
<?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-->



    <bean id="userService" class="stukk.Service.Impl.UserServiceImpl" autowire="byType"/>

    <bean id="userDao" class="stukk.Dao.Impl.UserDaoImpl">
        <property name="array">
            <array>
                <value>1</value>
                <value>2</value>
                <value>3</value>
                <value>4</value>
            </array>
        </property>

        <property name="list">
            <list>
                <value>A</value>
                <value>B</value>
                <value>C</value>
                <value>D</value>
            </list>
        </property>

        <property name="set">
            <set>
                <value>a</value>
                <value>b</value>
                <value>c</value>
                <value>d</value>
            </set>
        </property>

        <property name="map">
            <map>
                <entry key="国家" value="中国"/>
                <entry key="省份" value="广东省"/>
                <entry key="市区" value="xx市"/>
            </map>
        </property>

        <property name="properties">
            <props>
                <prop key="电子">烟假</prop>
                <prop key="尼古">丁真</prop>
            </props>
        </property>

    </bean>

</beans>

运行结果:

ok ,今天就到这,以后继续更新!坚持学习!!!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stu_kk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值