Spring学习笔记

Posted java李博士

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring学习笔记相关的知识,希望对你有一定的参考价值。

spring课堂笔记

框架: 一个java应用程序的半成品项目,该项目中对java的软件开发进行了一部分的封装和定义标准,我们使用时 只需要学习框架,则会学会使用该框架开发新项目,再开发中使用框架可以提高开发效率,有利于团队开发。

​ 缺点:

​ 1,需要导入大量的jar包,会出现版本冲突

​ 2,项目运行效率低

​ 优点:

​ 1,提高开发效率

​ 2,利于团队开发

​ 3,有利于后期的维护

springBoot mybatis ---> SM

springmvc spring mybatis ---> SSM

struts2 spring hibernate ---> SSH

目标:

​ spring简介

​ spring核心

​ IOC/DI

​ AOP

​ 声明式事务管理

​ jdbctemplete

spring简介

Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control: 反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多 著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。

轻量级框架, Java EE的春天,当前最主流框架。

IOC/DI 反转控制 依赖注入

AOP 面向切面编程

Spring的发展历史:

​ 1997 年 IBM 提出了 EJB 的思想

​ 1998 年,SUN 制定开发标准规范 EJB1.0

​ 1999 年,EJB1.1 发布

​ 2001 年,EJB2.0 发布

​ 2003 年,EJB2.1 发布

​ 2006 年,EJB3.0 发布

Rod Johnson(spring 之父)

​ Expert One-to-One J2EE Design and Development(2002)

​ 阐述了 J2EE 使用 EJB 开发设计的优点及解决方案

​ Expert One-to-One J2EE Development without EJB(2004)

​ 阐述了 J2EE 开发不使用 EJB 的解决方式(Spring 雏形)

2017 年 9 月份发布了 spring 的最新版本 spring 5.0 通用版(GA)

发展优势

方便解耦,简化开发

通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造 成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可 以更专注于上层的应用。

AOP 编程的支持

通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。

声明式事务的支持

可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理, 提高开发效率和质量。

方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可 做的事情。

方便集成各种优秀框架

Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz 等)的直接支持。

降低 JavaEE API的使用难度

Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的 使用难度大为降低。

Java源码是经典学习范例

Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以 及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。

通俗的说:

​ 使现有技术更加易用,推进编码最佳实践

​ 老技术新用法

​ 降低耦合性【亲密度】

七大部分组成

image

IoC容器【控制翻转/依赖注入】

AOP实现

数据访问支持

简化JDBC/ORM 框架

声明式事务

spring的web支持

spring的单元测试

Spring在mvc中的江湖位置:

img

耦合度

耦合度是再java中,类与类之间的关系,可以是 亲密度.

程序编程思想: 高内聚,低耦合

最好是再编译期不存在问题即可

public class TestJDBC {
    public static void main(String[] args) throws  Exception {
        // 加载驱动(使用Driver来创建该类的对象,放入到内存中)   关系: 非常亲密    高耦合
        // 降低耦合度     低耦合  解耦   : 使用反射机制来创建对象,并维护类与类之间的关系
        //DriverManager.registerDriver(new Driver());  // 硬编码
        Class.forName("com.mysql.jdbc.Driver");

        // 建立连接
        Connection connection = DriverManager.getConnection("jdbc:mysql:///duobiao", "root", "root");
        System.out.println( connection);
    }
}

工厂模式模仿spring的IOC

定义一个dao层并实现改层的方法(save() update() ),编写一个service层来调用dao层中的方法来实现功能.

UserDao.java

public interface UserDao {

    public void save();

    public void update();
    
}

UserDaoImpl.java

public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("----------添加数据(Mysql)----------");
    }

    @Override
    public void update() {
        System.out.println("=============修改数据(Mysql)========");
    }
}

UserOracleDaoIml.java

public class UserOracleDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("------添加数据(oracle)--------");
    }

    @Override
    public void update() {
        System.out.println("+++修改数据(oracle)+++");
    }
}

UserServer.java

public class UserService {
    // 使用servie中的业务方法来调用dao中的方法来使用
    //UserDao userDao = new UserDaoImpl();
    UserDao userDao = new UserOracleDaoImpl();
    // 分析缺点:  userServer和UserDao之间的耦合性较高    userDao不存在    硬编码方式
    //   解决 :  降低耦合  解耦   :   反射机制(BeanFactory)

    public void insert(){
        userDao.save();
    }

    public void update(){
        userDao.update();
    }
}

UserUI.java

public class UserUI {

    public static void main(String[] args) {
        UserService userService = new UserService();

        userService.insert();

        userService.update();
    }
}

分析

​ 再UserServie中会发现,如果想要执行dao中的方法实现添加,那么必须使用 new 来创建userDao对象,如果连接不同的数据库,则 new 后的类也要随之改变,这种为硬编码方式,该方式不利于代码更改,类与类之间的耦合性较高,不符合"高内聚,低耦合"的编程思想。

解决

​ 可以使用反射机制与工厂模式来创建一个工厂类,通过配置文件形式来搭建类与类之间的关系.使用反射机制的原来来代替原有的new来创建对象的过程。

BeanFactory.java

public class BeanFactory {

    private static Properties properties = new Properties();
    static{
        InputStream rs = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            properties.load(rs);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 定义一个静态方法,来使用java的反射机制创建对象
    public static Object getInstance(String key){
        Object object = null;
        try {
            Class<?> ac = Class.forName(properties.getProperty(key));
            object = ac.newInstance();
        } catch (Exception e){
            e.printStackTrace();
        }
        return object;
    }
}

bean.properties

# key = value
userDao=cn.hd.dao.impl.UserOracleDaoImpl
userService=cn.hd.service.UserService

则userSercie中的对象创建就变为了以beanFactory的模式创建了

 //   解决 :  降低耦合  解耦   :   反射机制(BeanFactory)
 UserDao userDao = (UserDao) BeanFactory.getInstance("userDao");

UserUI中的创建userService的对象创建也变为了beanFactory的模式创建了

 public static void main(String[] args) {
        //UserService userService = new UserService();
        // 改变后
        UserService userService = (UserService) BeanFactory.getInstance("userService");
        userService.insert();
        userService.update();
    }

总结

​ 使用工厂模式和反射机制来实现以配置文件的形式创建对象的模式,可以释放类与类之间的耦合度,实现解耦

缺点

​ 类与类之间的关系还不能完全解耦,那么我们就可以学习使用spring框架来实现完全解耦了。

spring入门案例

实现步骤:

​ 1,再pom.xml文件中配置spring的核心jar包坐标

		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.21.RELEASE</version>
        </dependency>

​ 2,再resoures下创建一个spring.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 创建一个UserDaoImpl的对象
		之前:
            UserDao userDao = new UserDaoImpl();
            userDao = cn.hd.dao.impl.UserDaoImpl  反射创建
         bean :  创建对象
            id : 创建对象后的唯一标识   对象名
            class : 类的全类名
            name : 创建对象后的对象名
            默认是使用无参的构造器创建对象,放入到IOC容器
            IOC : 反转控制    控制反转    创建对象
     -->
    <bean id="userDao" class="cn.hd.dao.impl.UserDaoImpl" ></bean>

    <bean id="ud" class="cn.hd.dao.impl.UserOracleDaoImpl"></bean>

    <bean name="userService" class="cn.hd.service.UserService"></bean>

</beans>

​ 3,编写测试类

@Test
    public void test1(){
        // 1,读取spring.xml配置,读取中或直接访问到bean标签,
        //      该标签就会把对应的对象创建成功,放入到spring的IOC容器中
        ClassPathXmlApplicationContext  cp = 
                    new ClassPathXmlApplicationContext("spring.xml");

        // 2,调用getBean("")从IOC容器中把userDao这个对象获取出来
        UserDao userDao = (UserDao) cp.getBean("userDao");

        System.out.println(userDao);
		//    根据目标资源类名来返回指定的对象
        UserService userService = cp.getBean("userService", UserService.class);
        System.out.println(userService);
    }

控制反转 IOC

IOC : 控制反转 创建对象 bean标签实现控制反转

​ 把java中创建对象的过程交给spring的核心配置文件【IOC容器】的过程

控制反转默认创建对象使用的是类的无参的构造器,创建后的对象的name/id名称必须唯一:

​ ![img](file:///C:\\Users\\ADMINI~1\\AppData\\Local\\Temp\\ksohtml940\\wps3.jpg)

<!-- 创建一个UserDaoImpl的对象
            UserDao userDao = new UserDaoImpl();
            userDao = cn.hd.dao.impl.UserDaoImpl  反射创建
         bean :  创建对象
            id : 创建对象后的唯一标识   对象名
            class : 类的全类名
            name : 创建对象后的对象名
            默认是使用无参的构造器创建对象,放入到IOC容器
            IOC : 反转控制    控制反转    创建对象
     -->
    <bean id="userDao" class="cn.hd.dao.impl.UserDaoImpl"></bean>

    <bean id="ud" class="cn.hd.dao.impl.UserOracleDaoImpl"></bean>

    <bean name="userService" class="cn.hd.service.UserService"></bean>

scope属性

scope : 用来设置spring容器创建对象的模式

​ prototype : 多例模式 每一从使用getBean()都会创建一个新对象

​ 生命周期: 初始化 (init-method) 服务(getBean) 销毁(java垃圾回收处理)

​ singleton : 单例模式 读取配置文件是创建该类的唯一对象,放入IOC容器中

​ 生命周期: 初始化 (init-method) 服务(getBean) 销毁(destory-method)

配置文件:

<bean id="userDao" class="cn.hd.dao.impl.UserDaoImpl"
      scope="singleton" init-method="init" destroy-method="destory"></bean>

测试:

	@Test
    public void test3(){
        ClassPathXmlApplicationContext cp
                = new ClassPathXmlApplicationContext("spring.xml");

        UserDao userDao1 = cp.getBean("userDao", UserDao.class);
        System.out.println(userDao1);
        UserDao userDao2 = cp.getBean("userDao", UserDao.class);
        System.out.println(userDao2);
        UserDao userDao3 = cp.getBean("userDao", UserDao.class);
        System.out.println(userDao3);

        cp.close();
    }

数据输入 DI

DI : 依赖注入 属性赋值 property标签来实现依赖注入

​ 为IOC容器中所创建的对象的属性进行赋值的过程

IOC/DI : 控制反转,依赖注入

1,使用set注入数据

​ A,对象的依赖注入 ref

​ B,简单数据类型的依赖注入 (基本数据类型+String) value

​ Bean创建对象时,默认采用的是无参的构造器 image

2,使用有参的构造器注入数据

​ 首先要再类中定义一个有参的构造器:

image

​ 使用有参的构造器来创建对象并进行数据注入

​ !image

3,使用p命令方式注入数据

注意:p标签模式注入,spring版本要再 5.xx 以上中使用

​ 现在spring.xml中定义p标签image

​ 使用p标签实现数据注入

​ P:简单属性=”值” p:对象属性-ref=”对象名”

image

4,集合数据的注入

​ 定义一个类,声明一些集合属性

public class Student {

    private int arr[];
    private List list;
    private Map map;
    private Properties ps;

    @Override
    public String toString() {
        return "Student{" +
                "arr=" + Arrays.toString(arr) +
                ", list=" + list +
                ", map=" + map +
                ", ps=" + ps +
                \'}\';
    }
	// 省略公共的get和set方法
}

​ spring.xml中实现数据注入

 <bean name="student" class="cn.hd.service.Student">
        <property name="arr">
            <list>
                <value>1001</value>
                <value>1002</value>
            </list>
        </property>

        <property name="list">
            <list>
                <value>李四</value>
                <value>王五</value>
                <ref bean="ud"></ref>
            </list>
        </property>

        <property name="map">
            <map>
                <entry key="a" value="aaaa"/>
                <entry key-ref="ud" value="bbbb"/>
                <entry key-ref="ud" value-ref="ud"/>
                <entry key="b" value-ref="ud"/>
                <entry key="b" value="bbbb"/>
            </map>
        </property>

        <!--<property name="ps">
            <props>
                <prop key="a">aaaa</prop>
                <prop key="b">bbbb</prop>
            </props>
        </property>-->
        <property name="ps">
            <value>
                a=aaaaaa
                b=bbbbbbbbbbbbbbbbbbbbbbbbb
            </value>
        </property>

    </bean>

​ 运行并测试

	@Test
    public void test4(){
        ClassPathXmlApplicationContext cp
                = new ClassPathXmlApplicationContext("spring.xml");
       
        Student student = cp.getBean("student", Student.class);
        System.out.println(student.toString());

    }

注解实现IOC/DI

再项目中如果有多张表的操作,则dao层和service创建对象和赋值的过程中会创建多个bean标签,该标签再spring.xml中就会有很多个,看着不合适,编写较为麻烦。

咱们就可以使用spring提供的注解来实现 IOC / DI

常见注解:

​ 注解方式将Bean的定义信息和Bean实现类结合在一起,Spring提供的注解有

​ @Component:实现Bean组件的定义,创建对象

​ @Repository :用于标注DAO类 创建对象 继承@Component

​ @Service :用于标注业务类 创建对象 继承@Component

​ @Controller :用于标注控制器类 创建对象 继承@Component

@Scope(value="singleton/prototype") 设置创建对象的模式(单例/多例)

使用@Autowired注解实现Bean的自动装配,默认按类型匹配,可以使用@Qualifier指定Bean的名称

注意: 注解形式可以省略get和set方法

​ @Value 为简单类型注入数据

​ @Atuowired 自动装配

​ @Qualifier(value="") 与@Autowired结合使用

​ @Resource(name = "ud") 根据name的名称实现数据注入

案例1:

​ 1,再spring的配置文件头部引入context标签的支持

image

​ 2,再配置文件中配置扫描包

image

​ 3,再每一个类前加入指定的注解

image

image

​ 4,再类中的属性中使用注解实现数据注入

image

​ 5,测试类

image

案例2:

​ 使用注解方式动态的从db.properties的配置文件中动态的获取连接数据库的四大组件值:

​ 1,创建db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///test
name=root
pwd=123456

​ 2,再配置文件中读取配置文件

<!-- 如果使用注解,则我们需要再spring.xml配置文件中,实现扫描包的配置
        自动扫描类前@component注解实现创建对象
        并扫描创建中的DI的注解实现数据的注入-->
    <context:component-scan base-package="cn.hd" />

    <!-- 引入外部配置文件 -->
    <context:property-placeholder location="classpath:db.properties"/>

​ 3,再类中使用@Value动态的实现数据注入

@Component(value = "jdu")
public class JDBCUtils {
        @Value("${driver}")
        private  String driver ;
        @Value("${url}")
        private String url ;
        @Value("${name}")
        private String username ;
        @Value("${pwd}")
        private String password ;


        @Override
    public String toString() {
        return "JDBCUtils{" +
                "driver=\'" + driver + \'\\\'\' +
                ", url=\'" + url + \'\\\'\' +
                ", username=\'" + username + \'\\\'\' +
                ", password=\'" + password + \'\\\'\' +
                \'}\';
    }
}

​ 4,测试

@Test
public void test2(){
   ClassPathXmlApplicationContext cp
                = new ClassPathXmlApplicationContext("spring.xml");
   JDBCUtils jdu = cp.getBean("jdu", JDBCUtils.class);

   System.out.println(jdu.toString());
 }

总结:

​ 1,如果是自己编写的java类,需要spring来统一管理,一般采用注解

​ 2,如果是调用框架中封装好的功能组件,一般我们采用xml配置形式

​ 3,注解方式一般改变都要重启,xml方式一旦数据注入,就要提供公共的get和set方法

spring的单元测试

spring整合的junit的单元测试后,每一次的调用都不需要再去直接读取配置文件了。

使用spring的测试有利于后期整合项目的单独测试,便于开发。

使用步骤:

​ 1,导入spring-test包

		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.2.RELEASE</version>
        </dependency>

​ 2,导入junit包 注意: 如果spring的是5.xxx以上,则junit必须是 4.12以上版本

		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

​ 3,再测试类中配置即可

// 把单元测试的功能交给了spring中整合的单元测试
@RunWith(SpringJUnit4ClassRunner.class)
// 读取spring.xml的核心配置文件,该IOC容器作用域整个类
@ContextConfiguration(locations = "classpath:spring.xml")
public class TestSpring2 {
    @Autowired
    private JDBCUtils jd;
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserService userService;
    @Test
    public void t1(){
        System.out.println(jd.toString());
    }

    @Test
    public void t2(){
        userDao.save();
    }
    @Test
    public void t3(){
        System.out.println(userService.toString());
    }
}

spring配置文件的拆分

以后我们想要编写项目时,需要再spring.xml中配置很多的文件信息,如果把所有的文件信息全部都配置到一个配置文件中,该文件就会很大,不利于项目的配置文件的拷贝。

再核心配置文件中引入另一个配置文件:

<!-- 引入另一个spring的配置文件 -->
<import resource="classpath:spring-db.xml"/>

AOP 面向切面编程

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

通俗说:面向切面编程,切面类,把通用的功能提取出来放入到一个类,该类再不同的功能中被多次的调用并使用,那么该类就是切面类。各个功能再经过了该切面类后,其功能就会实现(功能)增强,实现代码的可重用性.

作用:

​ 在程序运行期间,不修改源码对已有方法进行增强。

优势:

​ 减少重复代码

​ 提高开发效率

​ 维护方便

画图理解:

image

springAOP的知识点

*Joinpoint(**连接点**)

以上是关于Spring学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

spring学习笔记AOP

Spring 学习笔记

Spring学习笔记--Spring IOC

Spring学习笔记:尝试Lombok简化实体类代码

Spring源码学习笔记

Spring4基础 学习笔记 ---- Bean

(c)2006-2024 SYSTEM All Rights Reserved IT常识