spring_springboot - CSDN
spring 订阅
Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于JEE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。 [1] 展开全文
Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于JEE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。 [1]
信息
范    围
Java应用
兴    起
2003年
外文名
Spring
中文名
Spring
功    能
使用基本的JavaBean代替EJB
目    的
解决企业应用开发的复杂性
spring简介
Spring是Java EE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002 年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。 [2]  Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。在整个框架中,各类型的功能被抽象成一个个的 Bean,这样就可以实现各种功能的管理,包括动态加载和切面编程。 [3]  Spring是独特的,因为若干个原因:它定位的领域是许多其他流行的framework没有的。Spring致力于提供一种方法管理你的业务对象。Spring是全面的和模块化的。Spring有分层的体系结构,这意味着你能选择使用它孤立的任何部分,它的架构仍然是内在稳定的。例如,你可能选择仅仅使用Spring来简单化JDBC的使用,或用来管理所有的业务对象。它的设计从底部帮助你编写易于测试的代码。Spring是用于测试驱动工程的理想的framework。Spring对你的工程来说,它不需要一个以上的framework。Spring是潜在地一站式解决方案,定位于与典型应用相关的大部分基础结构。它也涉及到其他framework没有考虑到的内容。
收起全文
  • Spring注解驱动开发

    2019-06-24 13:39:54
    Spring注解驱动开发》是一套帮助我们深入了解Spring原理机制的教程; 现今SpringBoot、SpringCloud技术非常火热,作为Spring之上的框架,他们大量使用到了Spring的一些底层注解、原理,比如@Conditional、@...
  • Spring4.0是 Spring 推出的一个重大版本升级,进一步加强了 Spring 作为 Java 领域第一开源平台的地位。Spring4.0 引入了众多 Java 开发者期盼的新特性,如泛型依赖注入、SpEL、校验及格式化框架、Rest风格的 WEB ...
  • Spring 1.简介 1.1.简介 简介 Spring : 春天 —>给软件行业带来了春天 2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。 2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布...

    Spring

    1.简介

    1.1.简介

    简介

    Spring : 春天 —>给软件行业带来了春天

    2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。

    2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。

    很难想象Rod Johnson的学历 , 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。

    Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术

    官网 : http://spring.io/

    官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/

    GitHub : https://github.com/spring-projects

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

    1.2.优点

    优点

    1、Spring是一个开源免费的框架 , 容器 .

    2、Spring是一个轻量级的框架 , 非侵入式的 .

    3、控制反转 IoC , 面向切面 Aop

    4、对事物的支持 , 对框架的支持

    一句话概括:

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

    1.3.组成

    组成

    在这里插入图片描述

    Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 .

    在这里插入图片描述

    组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

    • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
    • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
    • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。
    • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
    • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
    • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
    • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

    1.4.扩展

    拓展

    Spring Boot与Spring Cloud

    • Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
    • Spring Cloud是基于Spring Boot实现的;
    • Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
    • Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
    • SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。

    在这里插入图片描述

    2.IOC理论推导

    IoC基础

    新建一个空白的maven项目

    2.1.分析实现

    分析实现

    我们先用我们原来的方式写一段代码 .

    1、先写一个UserDao接口

    public interface UserDao {
       public void getUser();
    }
    

    2、再去写Dao的实现类

    public class UserDaoImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("获取用户数据");
      }
    }
    

    3、然后去写UserService的接口

    public interface UserService {
       public void getUser();
    }
    

    4、最后写Service的实现类

    public class UserServiceImpl implements UserService {
       private UserDao userDao = new UserDaoImpl();
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }
    

    5、测试一下

    @Test
    public void test(){
       UserService service = new UserServiceImpl();
       service.getUser();
    }
    

    这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .

    把Userdao的实现类增加一个 .

    public class UserDaoMySqlImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("MySql获取用户数据");
      }
    }
    

    紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现

    public class UserServiceImpl implements UserService {
       private UserDao userDao = new UserDaoMySqlImpl();
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }
    

    在假设, 我们再增加一个Userdao的实现类 .

    public class UserDaoOracleImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("Oracle获取用户数据");
      }
    }
    

    那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .

    那我们如何去解决呢 ?

    我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .

    public class UserServiceImpl implements UserService {
       private UserDao userDao;
    // 利用set实现
       public void setUserDao(UserDao userDao) {
           this.userDao = userDao;
      }
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }
    

    现在去我们的测试类里 , 进行测试 ;

    @Test
    public void test(){
       UserServiceImpl service = new UserServiceImpl();
       service.setUserDao( new UserDaoMySqlImpl() );
       service.getUser();
       //那我们现在又想用Oracle去实现呢
       service.setUserDao( new UserDaoOracleImpl() );
       service.getUser();
    }
    

    大家发现了区别没有 ? 可能很多人说没啥区别 . 但是同学们 , 他们已经发生了根本性的变化 , 很多地方都不一样了 . 仔细去思考一下 , 以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .

    这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

    2.2.IOC本质

    IOC本质

    控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

    在这里插入图片描述
    IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

    Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

    在这里插入图片描述

    采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

    控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

    3.HelloSpring

    导入Jar包

    注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 .

    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-webmvc</artifactId>
       <version>5.1.10.RELEASE</version>
    </dependency>
    

    编写代码

    1、编写一个Hello实体类

    public class Hello {
       private String name;
    
       public String getName() {
           return name;
      }
       public void setName(String name) {
           this.name = name;
      }
    
       public void show(){
           System.out.println("Hello,"+ name );
      }
    }
    

    2、编写我们的spring文件 , 这里我们命名为beans.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就是java对象 , 由Spring创建和管理-->
       <bean id="hello" class="com.kuang.pojo.Hello">
           <property name="name" value="Spring"/>
       </bean>
    
    </beans>
    

    3、我们可以去进行测试了 .

    @Test
    public void test(){
       //解析beans.xml文件 , 生成管理相应的Bean对象
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       //getBean : 参数即为spring配置文件中bean的id .
       Hello hello = (Hello) context.getBean("hello");
       hello.show();
    }
    

    思考

    • Hello 对象是谁创建的 ? hello 对象是由Spring创建的
    • Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的

    这个过程就叫控制反转 :

    • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
    • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .

    依赖注入 : 就是利用set方法来进行注入的.

    IOC是一种编程思想,由主动的编程变成被动的接收

    可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .

    修改案例一

    我们在案例一中, 新增一个Spring配置文件beans.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="MysqlImpl" class="com.kuang.dao.impl.UserDaoMySqlImpl"/>
       <bean id="OracleImpl" class="com.kuang.dao.impl.UserDaoOracleImpl"/>
    
       <bean id="ServiceImpl" class="com.kuang.service.impl.UserServiceImpl">
           <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
           <!--引用另外一个bean , 不是用value 而是用 ref-->
           <property name="userDao" ref="OracleImpl"/>
       </bean>
    
    </beans>
    

    测试!

    @Test
    public void test2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
       serviceImpl.getUser();
    }
    

    OK , 到了现在 , 我们彻底不用再程序中去改动了 , 要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配 !

    4.IOC创建对象方式

    4.1.通过无参构造方法来创建

    通过无参构造方法来创建

    1、User.java

    public class User {
    
       private String name;
    
       public User() {
           System.out.println("user无参构造方法");
      }
    
       public void setName(String name) {
           this.name = name;
      }
    
       public void show(){
           System.out.println("name="+ name );
      }
    
    }
    

    2、beans.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.kuang.pojo.User">
           <property name="name" value="kuangshen"/>
       </bean>
    
    </beans>
    

    3、测试类

    @Test
    public void test(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       //在执行getBean的时候, user已经创建好了 , 通过无参构造
       User user = (User) context.getBean("user");
       //调用对象的方法 .
       user.show();
    }
    

    结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!

    4.2.通过有参构造方法来创建

    通过有参构造方法来创建

    1、UserT . java

    public class UserT {
    
       private String name;
    
       public UserT(String name) {
           this.name = name;
      }
    
       public void setName(String name) {
           this.name = name;
      }
    
       public void show(){
           System.out.println("name="+ name );
      }
    
    }
    

    2、beans.xml 有三种方式编写

    <!-- 第一种根据index参数下标设置 -->
    <bean id="userT" class="com.kuang.pojo.UserT">
       <!-- index指构造方法 , 下标从0开始 -->
       <constructor-arg index="0" value="kuangshen2"/>
    </bean>
    <!-- 第二种根据参数名字设置 -->
    <bean id="userT" class="com.kuang.pojo.UserT">
       <!-- name指参数名 -->
       <constructor-arg name="name" value="kuangshen2"/>
    </bean>
    <!-- 第三种根据参数类型设置 -->
    <bean id="userT" class="com.kuang.pojo.UserT">
       <constructor-arg type="java.lang.String" value="kuangshen2"/>
    </bean>
    

    3、测试

    @Test
    public void testT(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserT user = (UserT) context.getBean("userT");
       user.show();
    }
    

    结论:在配置文件加载的时候。其中管理的对象都已经初始化了!

    5.Spring配置

    5.1.别名

    别名

    alias 设置别名 , 为bean设置别名 , 可以设置多个别名

    <!--设置别名:在获取Bean的时候可以使用别名获取-->
    <alias name="userT" alias="userNew"/>
    

    5.2.Bean的配置

    Bean的配置

    <!--bean就是java对象,由Spring创建和管理-->
    
    <!--
       id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
       如果配置id,又配置了name,那么name是别名
       name可以设置多个别名,可以用逗号,分号,空格隔开
       如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;
    
    class是bean的全限定名=包名+类名
    -->
    <bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
       <property name="name" value="Spring"/>
    </bean>
    

    5.3.import

    import

    团队的合作通过import来实现 .

    <import resource="{path}/beans.xml"/>
    

    6.依赖注入(DI)

    Dependency Injection

    概念

    • 依赖注入(Dependency Injection,DI)。

    • 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .

    • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .

    6.1.构造器注入

    构造器注入

    我们在之前的案例已经讲过了

    6.2.Set 注入 (重点)

    Set 注入 (重点)

    要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .

    测试pojo类 :

    Address.java

     public class Address {
     
         private String address;
     
         public String getAddress() {
             return address;
        }
     
         public void setAddress(String address) {
             this.address = address;
        }
     }
    

    Student.java

     package com.kuang.pojo;
     
     import java.util.List;
     import java.util.Map;
     import java.util.Properties;
     import java.util.Set;
     
     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 Properties info;
     
         public void setName(String name) {
             this.name = name;
        }
     
         public void setAddress(Address address) {
             this.address = address;
        }
     
         public void setBooks(String[] books) {
             this.books = books;
        }
     
         public void setHobbys(List<String> hobbys) {
             this.hobbys = hobbys;
        }
     
         public void setCard(Map<String, String> card) {
             this.card = card;
        }
     
         public void setGames(Set<String> games) {
             this.games = games;
        }
     
         public void setWife(String wife) {
             this.wife = wife;
        }
     
         public void setInfo(Properties info) {
             this.info = info;
        }
     
         public void show(){
             System.out.println("name="+ name
                     + ",address="+ address.getAddress()
                     + ",books="
            );
             for (String book:books){
                 System.out.print("<<"+book+">>\t");
            }
             System.out.println("\n爱好:"+hobbys);
     
             System.out.println("card:"+card);
     
             System.out.println("games:"+games);
     
             System.out.println("wife:"+wife);
     
             System.out.println("info:"+info);
     
        }
     }
    

    6.3.扩展的注入

    1、常量注入

     <bean id="student" class="com.kuang.pojo.Student">
         <property name="name" value="小明"/>
     </bean>
    

    测试:

     @Test
     public void test01(){
         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     
         Student student = (Student) context.getBean("student");
     
         System.out.println(student.getName());
     
     }
    

    2、Bean注入

    注意点:这里的值是一个引用,ref

     <bean id="addr" class="com.kuang.pojo.Address">
         <property name="address" value="重庆"/>
     </bean>
     
     <bean id="student" class="com.kuang.pojo.Student">
         <property name="name" value="小明"/>
         <property name="address" ref="addr"/>
     </bean>
    

    3、数组注入

     <bean id="student" class="com.kuang.pojo.Student">
         <property name="name" value="小明"/>
         <property name="address" ref="addr"/>
         <property name="books">
             <array>
                 <value>西游记</value>
                 <value>红楼梦</value>
                 <value>水浒传</value>
             </array>
         </property>
     </bean>
    

    4、List注入

     <property name="hobbys">
         <list>
             <value>听歌</value>
             <value>看电影</value>
             <value>爬山</value>
         </list>
     </property>
    

    5、Map注入

     <property name="card">
         <map>
             <entry key="中国邮政" value="456456456465456"/>
             <entry key="建设" value="1456682255511"/>
         </map>
     </property>
    

    6、set注入

     <property name="games">
         <set>
             <value>LOL</value>
             <value>BOB</value>
             <value>COC</value>
         </set>
     </property>
    

    7、Null注入

     <property name="wife"><null/></property>
    

    8、Properties注入

     <property name="info">
         <props>
             <prop key="学号">20190604</prop>
             <prop key="性别">男</prop>
             <prop key="姓名">小明</prop>
         </props>
     </property>
    

    测试结果:
    在这里插入图片描述

    9、p命名和c命名注入

    p命名和c命名注入

    User.java :【注意:这里没有有参构造器!】

     public class User {
         private String name;
         private int age;
     
         public void setName(String name) {
             this.name = name;
        }
     
         public void setAge(int age) {
             this.age = age;
        }
     
         @Override
         public String toString() {
             return "User{" +
                     "name='" + name + '\'' +
                     ", age=" + age +
                     '}';
        }
     }
    

    1、P命名空间注入 : 需要在头文件中加入约束文件

     导入约束 : xmlns:p="http://www.springframework.org/schema/p"
     
     <!--P(属性: properties)命名空间 , 直接注入属性-->
     <bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
    

    2、c 命名空间注入 : 需要在头文件中加入约束文件

     导入约束 : xmlns:c="http://www.springframework.org/schema/c"
     <!--C(构造: Constructor)命名空间 , 使用构造器注入-->
     <bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>
    

    发现问题:爆红了,刚才我们没有写有参构造!

    解决:把有参构造器加上,这里也能知道,c 就是所谓的构造器注入!

    测试代码:

     @Test
     public void test02(){
         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
         User user = (User) context.getBean("user");
         System.out.println(user);
     }
    

    6.4.Bean的作用域

    Bean的作用域

    在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .
    在这里插入图片描述

    几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。

    Singleton(单例模式)

    当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

     <bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">
    

    测试:

     @Test
     public void test03(){
         ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
         User user = (User) context.getBean("user");
         User user2 = (User) context.getBean("user");
         System.out.println(user==user2);
     }
    

    Prototype(原型模式)

    当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

     <bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
      或者
     <bean id="account" class="com.foo.DefaultAccount" singleton="false"/>
    

    Request

    当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

     <bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
    

    针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

    Session

    当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

     <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
    

    针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。

    7.Bean的自动装配

    自动装配说明

    • 自动装配是使用spring满足bean依赖的一种方法
    • spring会在应用上下文中为某个bean寻找其依赖的bean。

    Spring中bean有三种装配机制,分别是:

    1. 在xml中显式配置;
    2. 在java中显式配置;
    3. 隐式的bean发现机制和自动装配。

    这里我们主要讲第三种:自动化的装配bean。

    Spring的自动装配需要从两个角度来实现,或者说是两个操作:

    1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
    2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

    组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

    推荐不使用自动装配xml配置 , 而使用注解 .

    **
    **

    测试环境搭建

    1、新建一个项目

    2、新建两个实体类,Cat Dog 都有一个叫的方法

    public class Cat {
       public void shout() {
           System.out.println("miao~");
      }
    }
    public class Dog {
       public void shout() {
           System.out.println("wang~");
      }
    }
    

    3、新建一个用户类 User

    public class User {
       private Cat cat;
       private Dog dog;
       private String str;
    }
    

    4、编写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
           http://www.springframework.org/schema/beans/spring-beans.xsd">
    
       <bean id="dog" class="com.kuang.pojo.Dog"/>
       <bean id="cat" class="com.kuang.pojo.Cat"/>
    
       <bean id="user" class="com.kuang.pojo.User">
           <property name="cat" ref="cat"/>
           <property name="dog" ref="dog"/>
           <property name="str" value="qinjiang"/>
       </bean>
    </beans>
    

    5、测试

    public class MyTest {
       @Test
       public void testMethodAutowire() {
           ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
           User user = (User) context.getBean("user");
           user.getCat().shout();
           user.getDog().shout();
      }
    }
    

    结果正常输出,环境OK

    7.1.byName

    byName

    autowire byName (按名称自动装配)

    由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。

    采用自动装配将避免这些错误,并且使配置简单化。

    测试:

    1、修改bean配置,增加一个属性 autowire=“byName”

    <bean id="user" class="com.kuang.pojo.User" autowire="byName">
       <property name="str" value="qinjiang"/>
    </bean>
    

    2、再次测试,结果依旧成功输出!

    3、我们将 cat 的bean id修改为 catXXX

    4、再次测试, 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。

    小结:

    当一个bean节点带有 autowire byName的属性时。

    1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。

    2. 去spring容器中寻找是否有此字符串名称id的对象。

    3. 如果有,就取出注入;如果没有,就报空指针异常。

    7.2.byType

    byType

    autowire byType (按类型自动装配)

    使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

    NoUniqueBeanDefinitionException
    

    测试:

    1、将user的bean配置修改一下 : autowire=“byType”

    2、测试,正常输出

    3、在注册一个cat 的bean对象!

    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="cat2" class="com.kuang.pojo.Cat"/>
    
    <bean id="user" class="com.kuang.pojo.User" autowire="byType">
       <property name="str" value="qinjiang"/>
    </bean>
    

    4、测试,报错:NoUniqueBeanDefinitionException

    5、删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

    这就是按照类型自动装配!

    7.3.使用注解

    使用注解

    jdk1.5开始支持注解,spring2.5开始全面支持注解。

    准备工作:利用注解的方式注入属性。

    1、在spring配置文件中引入context文件头

    xmlns:context="http://www.springframework.org/schema/context"
    
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    

    2、开启属性注解支持!

    <context:annotation-config/>
    

    @Autowired

    • @Autowired是按类型自动转配的,不支持id匹配。
    • 需要导入 spring-aop的包!

    测试:

    1、将User类中的set方法去掉,使用@Autowired注解

    public class User {
       @Autowired
       private Cat cat;
       @Autowired
       private Dog dog;
       private String str;
    
       public Cat getCat() {
           return cat;
      }
       public Dog getDog() {
           return dog;
      }
       public String getStr() {
           return str;
      }
    }
    

    2、此时配置文件内容

    <context:annotation-config/>
    
    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="user" class="com.kuang.pojo.User"/>
    

    3、测试,成功输出结果!

    【小狂神科普时间】

    @Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。

    //如果允许对象为null,设置required = false,默认为true
    @Autowired(required = false)
    private Cat cat;
    

    @Qualifier

    • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配
    • @Qualifier不能单独使用。

    测试实验步骤:

    1、配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!

    <bean id="dog1" class="com.kuang.pojo.Dog"/>
    <bean id="dog2" class="com.kuang.pojo.Dog"/>
    <bean id="cat1" class="com.kuang.pojo.Cat"/>
    <bean id="cat2" class="com.kuang.pojo.Cat"/>
    

    2、没有加Qualifier测试,直接报错

    3、在属性上添加Qualifier注解

    @Autowired
    @Qualifier(value = "cat2")
    private Cat cat;
    @Autowired
    @Qualifier(value = "dog2")
    private Dog dog;
    

    测试,成功输出!

    @Resource

    • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
    • 其次再进行默认的byName方式进行装配;
    • 如果以上都不成功,则按byType的方式自动装配。
    • 都不成功,则报异常。

    实体类:

    public class User {
       //如果允许对象为null,设置required = false,默认为true
       @Resource(name = "cat2")
       private Cat cat;
       @Resource
       private Dog dog;
       private String str;
    }
    

    beans.xml

    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="cat1" class="com.kuang.pojo.Cat"/>
    <bean id="cat2" class="com.kuang.pojo.Cat"/>
    
    <bean id="user" class="com.kuang.pojo.User"/>
    

    测试:结果OK

    配置文件2:beans.xml , 删掉cat2

    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="cat1" class="com.kuang.pojo.Cat"/>
    

    实体类上只保留注解

    @Resource
    private Cat cat;
    @Resource
    private Dog dog;
    

    结果:OK

    结论:先进行byName查找,失败;再进行byType查找,成功。

    小结

    @Autowired与@Resource异同:

    1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

    2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用

    3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

    它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

    8.使用注解开发

    说明

    在spring4之后,想要使用注解形式,必须得要引入aop的包

    在这里插入图片描述

    在配置文件当中,还得要引入一个context约束

    <?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
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    
    </beans>
    

    8.1.Bean的实现

    我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!

    1、配置扫描哪些包下的注解

    <!--指定注解扫描包-->
    <context:component-scan base-package="com.kuang.pojo"/>
    

    2、在指定包下编写类,增加注解

    @Component("user")
    // 相当于配置文件中 <bean id="user" class="当前注解的类"/>
    public class User {
       public String name = "秦疆";
    }
    

    3、测试

    @Test
    public void test(){
       ApplicationContext applicationContext =
           new ClassPathXmlApplicationContext("beans.xml");
       User user = (User) applicationContext.getBean("user");
       System.out.println(user.name);
    }
    

    8.2.属性注入

    使用注解注入属性

    1、可以不用提供set方法,直接在直接名上添加@value(“值”)

    @Component("user")
    // 相当于配置文件中 <bean id="user" class="当前注解的类"/>
    public class User {
       @Value("秦疆")
       // 相当于配置文件中 <property name="name" value="秦疆"/>
       public String name;
    }
    

    2、如果提供了set方法,在set方法上添加@value(“值”);

    @Component("user")
    public class User {
    
       public String name;
    
       @Value("秦疆")
       public void setName(String name) {
           this.name = name;
      }
    }
    

    8.3.衍生注解

    我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!

    @Component三个衍生注解

    为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

    • @Controller:controller层
    • @Service:service层
    • @Repository:dao层

    写上这些注解,就相当于将这个类交给Spring管理装配了!

    8.4.自动装配注解

    在Bean的自动装配已经讲过了,可以回顾!

    8.5.作用域

    @scope

    • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
    • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
    @Controller("user")
    @Scope("prototype")
    public class User {
       @Value("秦疆")
       public String name;
    }
    

    8.6.小结

    XML与注解比较

    • XML可以适用任何场景 ,结构清晰,维护方便
    • 注解不是自己提供的类使用不了,开发简单方便

    xml与注解整合开发 :推荐最佳实践

    • xml管理Bean
    • 注解完成属性注入
    • 使用过程中, 可以不用扫描,扫描是为了类上的注解
    <context:annotation-config/>  
    

    作用:

    • 进行注解驱动注册,从而使注解生效

    • 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册

    • 如果不扫描包,就需要手动配置bean

    • 如果不加注解驱动,则注入的值为null!

    9.基于Java类进行配置

    JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。

    测试:

    1、编写一个实体类,Dog

    @Component  //将这个类标注为Spring的一个组件,放到容器中!
    public class Dog {
       public String name = "dog";
    }
    

    2、新建一个config配置包,编写一个MyConfig配置类

    @Configuration  //代表这是一个配置类
    public class MyConfig {
    
       @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
       public Dog dog(){
           return new Dog();
      }
    
    }
    

    3、测试

    @Test
    public void test2(){
       ApplicationContext applicationContext =
               new AnnotationConfigApplicationContext(MyConfig.class);
       Dog dog = (Dog) applicationContext.getBean("dog");
       System.out.println(dog.name);
    }
    

    4、成功输出结果!

    导入其他配置如何做呢?

    1、我们再编写一个配置类!

    @Configuration  //代表这是一个配置类
    public class MyConfig2 {
    }
    

    2、在之前的配置类中我们来选择导入这个配置类

    @Configuration
    @Import(MyConfig2.class)  //导入合并其他配置类,类似于配置文件中的 inculde 标签
    public class MyConfig {
    
       @Bean
       public Dog dog(){
           return new Dog();
      }
    
    }
    

    关于这种Java类的配置方式,我们在之后的SpringBoot 和 SpringCloud中还会大量看到,我们需要知道这些注解的作用即可!

    10.代理模式

    为什么要学习代理模式,因为AOP的底层机制就是动态代理!

    代理模式:

    • 静态代理
    • 动态代理

    学习aop之前 , 我们要先了解一下代理模式!

    在这里插入图片描述

    10.1静态代理

    静态代理角色分析

    • 抽象角色 : 一般使用接口或者抽象类来实现

    • 真实角色 : 被代理的角色

    • 代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .

    • 客户 : 使用代理角色来进行一些操作 .

    代码实现

    Rent . java 即抽象角色

    //抽象角色:租房
    public interface Rent {
       public void rent();
    }
    

    Host . java 即真实角色

    //真实角色: 房东,房东要出租房子
    public class Host implements Rent{
       public void rent() {
           System.out.println("房屋出租");
      }
    }
    

    Proxy . java 即代理角色

    //代理角色:中介
    public class Proxy implements Rent {
    
       private Host host;
       public Proxy() { }
       public Proxy(Host host) {
           this.host = host;
      }
    
       //租房
       public void rent(){
           seeHouse();
           host.rent();
           fare();
      }
       //看房
       public void seeHouse(){
           System.out.println("带房客看房");
      }
       //收中介费
       public void fare(){
           System.out.println("收中介费");
      }
    }
    

    Client . java 即客户

    //客户类,一般客户都会去找代理!
    public class Client {
       public static void main(String[] args) {
           //房东要租房
           Host host = new Host();
           //中介帮助房东
           Proxy proxy = new Proxy(host);
    
           //你去找中介!
           proxy.rent();
      }
    }
    

    分析:在这个过程中,你直接接触的就是中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式,程序源自于生活,所以学编程的人,一般能够更加抽象的看待生活中发生的事情。

    静态代理的好处:

    • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
    • 公共的业务由代理来完成 . 实现了业务的分工 ,
    • 公共业务发生扩展时变得更加集中和方便 .

    缺点 :

    • 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .

    我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !

    10.2.静态代理再理解

    同学们练习完毕后,我们再来举一个例子,巩固大家的学习!

    练习步骤:

    1、创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!

    //抽象角色:增删改查业务
    public interface UserService {
       void add();
       void delete();
       void update();
       void query();
    }
    

    2、我们需要一个真实对象来完成这些增删改查操作

    //真实对象,完成增删改查操作的人
    public class UserServiceImpl implements UserService {
    
       public void add() {
           System.out.println("增加了一个用户");
      }
    
       public void delete() {
           System.out.println("删除了一个用户");
      }
    
       public void update() {
           System.out.println("更新了一个用户");
      }
    
       public void query() {
           System.out.println("查询了一个用户");
      }
    }
    

    3、需求来了,现在我们需要增加一个日志功能,怎么实现!

    • 思路1 :在实现类上增加代码 【麻烦!】
    • 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!

    4、设置一个代理类来处理日志!代理角色

    //代理角色,在这里面增加日志的实现
    public class UserServiceProxy implements UserService {
       private UserServiceImpl userService;
    
       public void setUserService(UserServiceImpl userService) {
           this.userService = userService;
      }
    
       public void add() {
           log("add");
           userService.add();
      }
    
       public void delete() {
           log("delete");
           userService.delete();
      }
    
       public void update() {
           log("update");
           userService.update();
      }
    
       public void query() {
           log("query");
           userService.query();
      }
    
       public void log(String msg){
           System.out.println("执行了"+msg+"方法");
      }
    
    }
    

    5、测试访问类:

    public class Client {
       public static void main(String[] args) {
           //真实业务
           UserServiceImpl userService = new UserServiceImpl();
           //代理类
           UserServiceProxy proxy = new UserServiceProxy();
           //使用代理类实现日志功能!
           proxy.setUserService(userService);
    
           proxy.add();
      }
    }
    

    OK,到了现在代理模式大家应该都没有什么问题了,重点大家需要理解其中的思想;

    我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想

    聊聊AOP:纵向开发,横向开发

    在这里插入图片描述

    10.3动态代理

    • 动态代理的角色和静态代理的一样 .

    • 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的

    • 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理

      • 基于接口的动态代理----JDK动态代理
      • 基于类的动态代理–cglib
      • 现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
      • 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!、

    JDK的动态代理需要了解两个类

    核心 : InvocationHandler 和 Proxy , 打开JDK帮助文档看看

    【InvocationHandler:调用处理程序】

    在这里插入图片描述

    Object invoke(Object proxy, 方法 method, Object[] args);
    //参数
    //proxy - 调用该方法的代理实例
    //method -所述方法对应于调用代理实例上的接口方法的实例。方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
    //args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
    

    【Proxy : 代理】

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    //生成代理类
    public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                     rent.getClass().getInterfaces(),this);
    }
    

    代码实现

    抽象角色和真实角色和之前的一样!

    Rent . java 即抽象角色

    //抽象角色:租房
    public interface Rent {
       public void rent();
    }
    

    Host . java 即真实角色

    //真实角色: 房东,房东要出租房子
    public class Host implements Rent{
       public void rent() {
           System.out.println("房屋出租");
      }
    }
    

    ProxyInvocationHandler. java 即代理角色

    public class ProxyInvocationHandler implements InvocationHandler {
       private Rent rent;
    
       public void setRent(Rent rent) {
           this.rent = rent;
      }
    
       //生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色
       public Object getProxy(){
           return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                   rent.getClass().getInterfaces(),this);
      }
    
       // proxy : 代理类 method : 代理类的调用处理程序的方法对象.
       // 处理代理实例上的方法调用并返回结果
       @Override
       public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
           seeHouse();
           //核心:本质利用反射实现!
           Object result = method.invoke(rent, args);
           fare();
           return result;
      }
    
       //看房
       public void seeHouse(){
           System.out.println("带房客看房");
      }
       //收中介费
       public void fare(){
           System.out.println("收中介费");
      }
    
    }
    

    Client . java

    //租客
    public class Client {
    
       public static void main(String[] args) {
           //真实角色
           Host host = new Host();
           //代理实例的调用处理程序
           ProxyInvocationHandler pih = new ProxyInvocationHandler();
           pih.setRent(host); //将真实角色放置进去!
           Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类!
           proxy.rent();
      }
    
    }
    

    核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!、

    10.4深化理解

    我们来使用动态代理实现代理我们后面写的UserService!

    我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!

    public class ProxyInvocationHandler implements InvocationHandler {
       private Object target;
    
       public void setTarget(Object target) {
           this.target = target;
      }
    
       //生成代理类
       public Object getProxy(){
           return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                   target.getClass().getInterfaces(),this);
      }
    
       // proxy : 代理类
       // method : 代理类的调用处理程序的方法对象.
       public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
           log(method.getName());
           Object result = method.invoke(target, args);
           return result;
      }
    
       public void log(String methodName){
           System.out.println("执行了"+methodName+"方法");
      }
    
    }
    

    测试!

    public class Test {
       public static void main(String[] args) {
           //真实对象
           UserServiceImpl userService = new UserServiceImpl();
           //代理对象的调用处理程序
           ProxyInvocationHandler pih = new ProxyInvocationHandler();
           pih.setTarget(userService); //设置要代理的对象
           UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
           proxy.delete();
      }
    }
    

    测试,增删改查,查看结果!

    10.5动态代理的好处

    静态代理有的它都有,静态代理没有的,它也有!

    • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
    • 公共的业务由代理来完成 . 实现了业务的分工 ,
    • 公共业务发生扩展时变得更加集中和方便 .
    • 一个动态代理 , 一般代理某一类业务
    • 一个动态代理可以代理多个类,代理的是接口!

    11.AOP

    11.1.什么是AOP

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

    在这里插入图片描述

    11.2.Aop在Spring中的作用

    提供声明式事务;允许用户自定义切面

    以下名词需要了解下:

    • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
    • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
    • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
    • 目标(Target):被通知对象。
    • 代理(Proxy):向目标对象应用通知之后创建的对象。
    • 切入点(PointCut):切面通知 执行的 “地点”的定义。
    • 连接点(JointPoint):与切入点匹配的执行点。

    在这里插入图片描述

    SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

    在这里插入图片描述

    即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 .

    11.3.使用Spring实现Aop

    【重点】使用AOP织入,需要导入一个依赖包!

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjweaver</artifactId>
       <version>1.9.4</version>
    </dependency>
    

    11.3.1.通过 Spring API 实现

    第一种方式

    首先编写我们的业务接口和实现类

    public interface UserService {
    
       public void add();
    
       public void delete();
    
       public void update();
    
       public void search();
    
    }
    public class UserServiceImpl implements UserService{
    
       @Override
       public void add() {
           System.out.println("增加用户");
      }
    
       @Override
       public void delete() {
           System.out.println("删除用户");
      }
    
       @Override
       public void update() {
           System.out.println("更新用户");
      }
    
       @Override
       public void search() {
           System.out.println("查询用户");
      }
    }
    

    然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强

    public class Log implements MethodBeforeAdvice {
    
       //method : 要执行的目标对象的方法
       //objects : 被调用的方法的参数
       //Object : 目标对象
       @Override
       public void before(Method method, Object[] objects, Object o) throws Throwable {
           System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");
      }
    }
    public class AfterLog implements AfterReturningAdvice {
       //returnValue 返回值
       //method被调用的方法
       //args 被调用的方法的对象的参数
       //target 被调用的目标对象
       @Override
       public void afterReturning(Object returnValue, Method method, Object[] args,Object target) throws Throwable {
           System.out.println("执行了" + target.getClass().getName()
           +"的"+method.getName()+"方法,"
           +"返回值:"+returnValue);
      }
    }
    

    最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .

    <?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:aop="http://www.springframework.org/schema/aop"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd">
    
       <!--注册bean-->
       <bean id="userService" class="com.kuang.service.UserServiceImpl"/>
       <bean id="log" class="com.kuang.log.Log"/>
       <bean id="afterLog" class="com.kuang.log.AfterLog"/>
    
       <!--aop的配置-->
       <aop:config>
           <!--切入点 expression:表达式匹配要执行的方法-->
           <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
           <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
           <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
           <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
       </aop:config>
    
    </beans>
    

    测试

    public class MyTest {
       @Test
       public void test(){
           ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
           UserService userService = (UserService) context.getBean("userService");
           userService.search();
      }
    }
    

    Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解这一块 .

    Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来 , 当执行领域业务时 , 将会把公共业务加进来 . 实现公共业务的重复利用 . 领域业务更纯粹 , 程序猿专注领域业务 , 其本质还是动态代理 .

    11.3.2.自定义类来实现Aop

    第二种方式

    目标业务类不变依旧是userServiceImpl

    第一步 : 写我们自己的一个切入类

    public class DiyPointcut {
    
       public void before(){
           System.out.println("---------方法执行前---------");
      }
       public void after(){
           System.out.println("---------方法执行后---------");
      }
       
    }
    

    去spring中配置

    <!--第二种方式自定义实现-->
    <!--注册bean-->
    <bean id="diy" class="com.kuang.config.DiyPointcut"/>
    
    <!--aop的配置-->
    <aop:config>
       <!--第二种方式:使用AOP的标签实现-->
       <aop:aspect ref="diy">
           <aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
           <aop:before pointcut-ref="diyPonitcut" method="before"/>
           <aop:after pointcut-ref="diyPonitcut" method="after"/>
       </aop:aspect>
    </aop:config>
    

    测试:

    public class MyTest {
       @Test
       public void test(){
           ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
           UserService userService = (UserService) context.getBean("userService");
           userService.add();
      }
    }
    

    11.3.4.使用注解实现

    第三种方式

    第一步:编写一个注解实现的增强类

    package com.kuang.config;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    
    @Aspect
    public class AnnotationPointcut {
       @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
       public void before(){
           System.out.println("---------方法执行前---------");
      }
    
       @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
       public void after(){
           System.out.println("---------方法执行后---------");
      }
    
       @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
       public void around(ProceedingJoinPoint jp) throws Throwable {
           System.out.println("环绕前");
           System.out.println("签名:"+jp.getSignature());
           //执行目标方法proceed
           Object proceed = jp.proceed();
           System.out.println("环绕后");
           System.out.println(proceed);
      }
    }
    

    第二步:在Spring配置文件中,注册bean,并增加支持注解的配置

    <!--第三种方式:注解实现-->
    <bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
    <aop:aspectj-autoproxy/>
    

    aop:aspectj-autoproxy:说明

    通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了
    
    <aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
    

    12.整合MyBatis

    步骤

    1、导入相关jar包

    junit

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

    mybatis

    <dependency>
       <groupId>org.mybatis</groupId>
       <artifactId>mybatis</artifactId>
       <version>3.5.2</version>
    </dependency>
    

    mysql-connector-java

    <dependency>
       <groupId>mysql</groupId>
       <artifactId>mysql-connector-java</artifactId>
       <version>5.1.47</version>
    </dependency>
    

    spring相关

    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-webmvc</artifactId>
       <version>5.1.10.RELEASE</version>
    </dependency>
    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-jdbc</artifactId>
       <version>5.1.10.RELEASE</version>
    </dependency>
    

    aspectJ AOP 织入器

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjweaver</artifactId>
       <version>1.9.4</version>
    </dependency>
    

    mybatis-spring整合包 【重点】

    <dependency>
       <groupId>org.mybatis</groupId>
       <artifactId>mybatis-spring</artifactId>
       <version>2.0.2</version>
    </dependency>
    

    配置Maven静态资源过滤问题!

    <build>
       <resources>
           <resource>
               <directory>src/main/java</directory>
               <includes>
                   <include>**/*.properties</include>
                   <include>**/*.xml</include>
               </includes>
               <filtering>true</filtering>
           </resource>
       </resources>
    </build>
    

    2、编写配置文件

    3、代码实现

    12.1回忆MyBatis

    编写pojo实体类

    package com.kuang.pojo;
    
    public class User {
       private int id;  //id
       private String name;   //姓名
       private String pwd;   //密码
    }
    

    实现mybatis的配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
           PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
           "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
       <typeAliases>
           <package name="com.kuang.pojo"/>
       </typeAliases>
    
       <environments default="development">
           <environment id="development">
               <transactionManager type="JDBC"/>
               <dataSource type="POOLED">
                   <property name="driver" value="com.mysql.jdbc.Driver"/>
                   <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                   <property name="username" value="root"/>
                   <property name="password" value="123456"/>
               </dataSource>
           </environment>
       </environments>
    
       <mappers>
           <package name="com.kuang.dao"/>
       </mappers>
    </configuration>
    

    UserDao接口编写

    public interface UserMapper {
       public List<User> selectUser();
    }
    

    接口对应的Mapper映射文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
           PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.kuang.dao.UserMapper">
    
       <select id="selectUser" resultType="User">
        select * from user
       </select>
    
    </mapper>
    

    测试类

    @Test
    public void selectUser() throws IOException {
    
       String resource = "mybatis-config.xml";
       InputStream inputStream = Resources.getResourceAsStream(resource);
       SqlSessionFactory sqlSessionFactory = newSqlSessionFactoryBuilder().build(inputStream);
       SqlSession sqlSession = sqlSessionFactory.openSession();
    
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
       List<User> userList = mapper.selectUser();
       for (User user: userList){
           System.out.println(user);
      }
    
       sqlSession.close();
    }
    

    12.2.MyBatis-Spring学习

    引入Spring之前需要了解mybatis-spring包中的一些重要类;

    http://www.mybatis.org/spring/zh/index.html

    在这里插入图片描述

    什么是 MyBatis-Spring?

    MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。

    知识基础

    在开始使用 MyBatis-Spring 之前,你需要先熟悉 Spring 和 MyBatis 这两个框架和有关它们的术语。这很重要

    MyBatis-Spring 需要以下版本:

    MyBatis-Spring MyBatis Spring 框架 Spring Batch Java
    2.0 3.5+ 5.0+ 4.0+ Java 8+
    1.3 3.4+ 3.2.2+ 2.1+ Java 6+

    如果使用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:

    <dependency>
       <groupId>org.mybatis</groupId>
       <artifactId>mybatis-spring</artifactId>
       <version>2.0.2</version>
    </dependency>
    

    要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory 和至少一个数据映射器类。

    在 MyBatis-Spring 中,可使用SqlSessionFactoryBean来创建 SqlSessionFactory。要配置这个工厂 bean,只需要把下面代码放在 Spring 的 XML 配置文件中:

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
     <property name="dataSource" ref="dataSource" />
    </bean>
    

    注意:SqlSessionFactory需要一个 DataSource(数据源)。这可以是任意的 DataSource,只需要和配置其它 Spring 数据库连接一样配置它就可以了。

    在基础的 MyBatis 用法中,是通过 SqlSessionFactoryBuilder 来创建 SqlSessionFactory 的。而在 MyBatis-Spring 中,则使用 SqlSessionFactoryBean 来创建。

    在 MyBatis 中,你可以使用 SqlSessionFactory 来创建 SqlSession。一旦你获得一个 session 之后,你可以使用它来执行映射了的语句,提交或回滚连接,最后,当不再需要它的时候,你可以关闭 session。

    SqlSessionFactory有一个唯一的必要属性:用于 JDBC 的 DataSource。这可以是任意的 DataSource 对象,它的配置方法和其它 Spring 数据库连接是一样的。

    一个常用的属性是 configLocation,它用来指定 MyBatis 的 XML 配置文件路径。它在需要修改 MyBatis 的基础配置非常有用。通常,基础配置指的是 < settings> 或 < typeAliases>元素。

    需要注意的是,这个配置文件并不需要是一个完整的 MyBatis 配置。确切地说,任何环境配置(),数据源()和 MyBatis 的事务管理器()都会被忽略。SqlSessionFactoryBean 会创建它自有的 MyBatis 环境配置(Environment),并按要求设置自定义环境的值。

    SqlSessionTemplate 是 MyBatis-Spring 的核心。作为 SqlSession 的一个实现,这意味着可以使用它无缝代替你代码中已经在使用的 SqlSession。

    模板可以参与到 Spring 的事务管理中,并且由于其是线程安全的,可以供多个映射器类使用,你应该总是用 SqlSessionTemplate 来替换 MyBatis 默认的 DefaultSqlSession 实现。在同一应用程序中的不同类之间混杂使用可能会引起数据一致性的问题。

    可以使用 SqlSessionFactory 作为构造方法的参数来创建 SqlSessionTemplate 对象。

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
     <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    

    现在,这个 bean 就可以直接注入到你的 DAO bean 中了。你需要在你的 bean 中添加一个 SqlSession 属性,就像下面这样:

    public class UserDaoImpl implements UserDao {
    
     private SqlSession sqlSession;
    
     public void setSqlSession(SqlSession sqlSession) {
       this.sqlSession = sqlSession;
    }
    
     public User getUser(String userId) {
       return sqlSession.getMapper...;
    }
    }
    

    按下面这样,注入 SqlSessionTemplate:

    <bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
     <property name="sqlSession" ref="sqlSession" />
    </bean>
    

    12.3.整合实现一

    1、引入Spring配置文件beans.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">
    

    2、配置数据源替换mybaits的数据源

    <!--配置数据源:数据源有非常多,可以使用第三方的,也可使使用Spring的-->
    <bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
       <property name="username" value="root"/>
       <property name="password" value="123456"/>
    </bean>
    

    3、配置SqlSessionFactory,关联MyBatis

    <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
       <property name="dataSource" ref="dataSource"/>
       <!--关联Mybatis-->
       <property name="configLocation" value="classpath:mybatis-config.xml"/>
       <property name="mapperLocations" value="classpath:com/kuang/dao/*.xml"/>
    </bean>
    

    4、注册sqlSessionTemplate,关联sqlSessionFactory;

    <!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
       <!--利用构造器注入-->
       <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    

    5、增加Dao接口的实现类;私有化sqlSessionTemplate

    public class UserDaoImpl implements UserMapper {
    
       //sqlSession不用我们自己创建了,Spring来管理
       private SqlSessionTemplate sqlSession;
    
       public void setSqlSession(SqlSessionTemplate sqlSession) {
           this.sqlSession = sqlSession;
      }
    
       public List<User> selectUser() {
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           return mapper.selectUser();
      }
       
    }
    

    6、注册bean实现

    <bean id="userDao" class="com.kuang.dao.UserDaoImpl">
       <property name="sqlSession" ref="sqlSession"/>
    </bean>
    

    7、测试

       @Test
       public void test2(){
           ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
           UserMapper mapper = (UserMapper) context.getBean("userDao");
           List<User> user = mapper.selectUser();
           System.out.println(user);
      }
    

    结果成功输出!现在我们的Mybatis配置文件的状态!发现都可以被Spring整合!

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
           PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
           "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
       <typeAliases>
           <package name="com.kuang.pojo"/>
       </typeAliases>
    </configuration>
    

    12.4.整合实现二

    mybatis-spring1.2.3版以上的才有这个 .

    官方文档截图 :

    dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不需要管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看

    在这里插入图片描述

    测试:

    1、将我们上面写的UserDaoImpl修改一下

    public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
       public List<User> selectUser() {
           UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
           return mapper.selectUser();
      }
    }
    

    2、修改bean的配置

    <bean id="userDao" class="com.kuang.dao.UserDaoImpl">
       <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    

    3、测试

    @Test
    public void test2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserMapper mapper = (UserMapper) context.getBean("userDao");
       List<User> user = mapper.selectUser();
       System.out.println(user);
    }
    

    总结 : 整合到spring以后可以完全不要mybatis的配置文件,除了这些方式可以实现整合之外,我们还可以使用注解来实现,这个等我们后面学习SpringBoot的时候还会测试整合!

    13.声明式事务

    13.1.回顾事务

    • 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!
    • 事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。

    事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。

    事务四个属性ACID

    1. 原子性(atomicity)

      • 事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用
    2. 一致性(consistency)

      • 一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
    3. 隔离性(isolation)

      • 可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏
    4. 持久性(durability)

      • 事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中

    测试

    将上面的代码拷贝到一个新项目中

    在之前的案例中,我们给userDao接口新增两个方法,删除和增加用户;

    //添加一个用户
    int addUser(User user);
    
    //根据id删除用户
    int deleteUser(int id);
    

    mapper文件,我们故意把 deletes 写错,测试!

    <insert id="addUser" parameterType="com.kuang.pojo.User">
    insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>
    
    <delete id="deleteUser" parameterType="int">
    deletes from user where id = #{id}
    </delete>
    

    编写接口的实现类,在实现类中,我们去操作一波

    public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {
    
       //增加一些操作
       public List<User> selectUser() {
           User user = new User(4,"小明","123456");
           UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
           mapper.addUser(user);
           mapper.deleteUser(4);
           return mapper.selectUser();
      }
    
       //新增
       public int addUser(User user) {
           UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
           return mapper.addUser(user);
      }
       //删除
       public int deleteUser(int id) {
           UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
           return mapper.deleteUser(id);
      }
    
    }
    

    测试

    @Test
    public void test2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserMapper mapper = (UserMapper) context.getBean("userDao");
       List<User> user = mapper.selectUser();
       System.out.println(user);
    }
    

    报错:sql异常,delete写错了

    结果 :插入成功!

    没有进行事务的管理;我们想让他们都成功才成功,有一个失败,就都失败,我们就应该需要事务!

    以前我们都需要自己手动管理事务,十分麻烦!

    但是Spring给我们提供了事务管理,我们只需要配置即可;

    13.2.Spring中的事务管理

    Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。

    编程式事务管理

    • 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
    • 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码

    声明式事务管理

    • 一般情况下比编程式事务好用。
    • 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
    • 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。

    使用Spring管理事务,注意头文件的约束导入 : tx

    xmlns:tx="http://www.springframework.org/schema/tx"
    
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">
    

    事务管理器

    • 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
    • 就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法。

    JDBC事务

    <bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
           <property name="dataSource" ref="dataSource" />
    </bean>
    

    配置好事务管理器后我们需要去配置事务的通知

    <!--配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
       <tx:attributes>
           <!--配置哪些方法使用什么样的事务,配置事务的传播特性-->
           <tx:method name="add" propagation="REQUIRED"/>
           <tx:method name="delete" propagation="REQUIRED"/>
           <tx:method name="update" propagation="REQUIRED"/>
           <tx:method name="search*" propagation="REQUIRED"/>
           <tx:method name="get" read-only="true"/>
           <tx:method name="*" propagation="REQUIRED"/>
       </tx:attributes>
    </tx:advice>
    

    spring事务传播特性:

    事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:

    • propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
    • propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
    • propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
    • propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
    • propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    • propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
    • propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作

    Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况。

    假设 ServiveX#methodX() 都工作在事务环境下(即都被 Spring 事务增强了),假设程序中存在如下的调用链:Service1#method1()->Service2#method2()->Service3#method3(),那么这 3 个服务类的 3 个方法通过 Spring 的事务传播机制都工作在同一个事务中。

    就好比,我们刚才的几个方法存在调用,所以会被放在一组事务当中!

    配置AOP

    导入aop的头文件!

    <!--配置aop织入事务-->
    <aop:config>
       <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.*(..))"/>
       <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
    

    进行测试

    删掉刚才插入的数据,再次测试!

    @Test
    public void test2(){
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       UserMapper mapper = (UserMapper) context.getBean("userDao");
       List<User> user = mapper.selectUser();
       System.out.println(user);
    }
    

    13.3.思考问题?

    为什么需要配置事务?

    • 如果不配置,就需要我们手动提交控制事务;
    • 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!

    B站地址:https://space.bilibili.com/95256449

    展开全文
  • 深入浅出Spring

    2019-06-24 13:06:09
    当前与Spring开发有关的课程视频已经很多,这些课程在知识面上都有着一定的广度和深度,但在实际的公司培训与高校授课时,本人发现学习编程重要的是:学生从一开始就能写出可运行的程序,唯有如此才可激发学生继续学...
  • 1.什么是Spring Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。  Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。  然而,Spring的用途不仅限于服务器端的...

    1.什么是Spring
    Spring是一个开源框架,它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。

       Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。
      然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
       目的:解决企业应用开发的复杂性
       功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
       范围:任何Java应用
       它是一个容器框架,用来装javabean(java对象),中间层框架(万能胶)可以起一个连接作用,比如说把Struts和hibernate粘合在一起运用。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

    2. 什么是控制反转(或依赖注入) 
       控制反转(IoC=Inversion of Control)IoC,用白话来讲,就是由容器控制程序之间的(依赖)关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:(依赖)控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
       IoC还有一个另外的名字:“依赖注入 (DI=Dependency Injection)”  ,即由容器动态的将某种依赖关系注入到组件之中 ,案例:实现Spring的IoC

    第一步:需要添加springIDE插件,配置相关依赖(插件如何安装点击打开链接)
    pom.xml  (1.spring-context   2.spring-orm  3.spring-web  4.spring-aspects)

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>zking</groupId>
      <artifactId>s1</artifactId>
      <packaging>war</packaging>
      <version>0.0.1-SNAPSHOT</version>
      <name>s1 Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
            <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>3.8.1</version>
                  <scope>test</scope>
            </dependency>
       
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.0.1.RELEASE</version>
        </dependency>
       
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>5.0.1.RELEASE</version>
        </dependency>
        <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-orm</artifactId>
                <version>5.0.1.RELEASE</version>
        </dependency>
     
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>5.0.1.RELEASE</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>s1</finalName>
      </build>
    </project>


    第二步:插件Spring的xml文件(右键-->new-->other-->spring-->Spring Bean Configuration File)

    注:创建spring的XML文件时,需要添加beans/aop/tx/context标签支持(勾上即可)
    ApplicationContext.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:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
        
        
    </beans>


    第三步:创建一个helloworld类

    package p1;
     
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    public class HelloWorld {
        private String name;
     
        public HelloWorld() {
            super();
            System.out.println("new HelloWorld()");
        }
        
        public HelloWorld(String name) {
            super();
            this.name = name;
        }
     
        public void init() {
            System.out.println("init.......");
        }
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }    
    }


    3. 如何在spring当中定义和配置一个JavaBean
    使用无参构造方法+set方法创建一个JavaBean
       1 id:在容器中查找Bean(对象)的id(唯一、且不能以/开头)
       2 class:bean(对象)的完整类名
       3 name:在容器中查找Bean(对象)的名字(唯一、允许以/开头、允许多个值,多个值之间用逗号或空格隔开)
       4 scope:(singleton|prototype)默认是singleton
         4.1 singleton(单例模式):在每个Spring IoC容器中一个bean定义对应一个对象实例
         4.2 prototype(原型模式/多例模式):一个bean(对象)定义对应多个对象实例
       4 abstract:将一个bean定义成抽象bean(抽象bean是不能实例化的),抽象类一定要定义成抽象bean,非抽象类也可以定义成抽象bean
       5 parent:指定一个父bean(必须要有继承关系才行)
       6 init-method:指定bean对象()的初始化方法
       7 使用有参数构造方法创建javaBean(java对象):constructor-arg

    第四步:在xml中创建bean(看不懂属性的,在第三点中有介绍)

    <bean id="helloworld" class="p1.HelloWorld" scope="prototype" name="a b c" init-method="init">
            <property name="name">
                <value>zs</value>
            </property>
    </bean>
        
        <bean id="helloworld2" class="p1.HelloWorld">
            <constructor-arg index="0">
                <value>zzz</value>
            </constructor-arg>
        </bean>


    第五步:写一个测试的类即可

    public static void main(String[] args) {
            //以前的写法
            HelloWorld helloWorld=new HelloWorld();
            helloWorld.setName("张三");
            System.out.println("hello"+helloWorld.getName());
            //-------------------------------------------------------------
            //Spring
            ApplicationContext applicationContext=new ClassPathXmlApplicationContext("ApplicationContext.xml");
            HelloWorld a = (HelloWorld)applicationContext.getBean("a");
            System.out.println("你好: "+a.getName());
            
            HelloWorld b = (HelloWorld)applicationContext.getBean("b");
            System.out.println("你好: "+b.getName());
            
            HelloWorld c = (HelloWorld)applicationContext.getBean("c");
            System.out.println("你好: "+c.getName());
            
            HelloWorld d = (HelloWorld)applicationContext.getBean("helloworld2");
            System.out.println("--------------------------------");
            System.out.println("你好: "+d.getName());
        }


    4. 简单属性的配置:
       8+1+3:8大基本数据类型+String+3个sql
                           java.util.Date      java.sql.Date    java.sql.Time    java.sql.Timestamp
       通过<value>标签赋值即可

    5. 复杂属性的配置
      5.1 JavaBean    ref bean=""
      5.2 List或数组
      5.3 Map
      5.4 Properties
    创建一个学生类(Student),定义这几个属性

    private HelloWold helloworld;
     
    private String []arr;
    private List list;
    private Map map;
    private Properties properties;
    在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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
    <bean id="helloworlds" class="p1.HelloWold">
    <property name="name">
    <value>张三</value>
    </property>
     
    </bean>
    <bean id="ss" class="p1.Student">
    <property name="helloworld">
    <ref bean="helloworlds"><!-- ref引用另一个对象 -->
    </property>
     
    <property name="arr">
    <list>
    <value>aa</value>
    <value>bb</value>
    <value>cc</value>
    <value>dd</value>
    </list>
    </property>
    <property name="list">
    <list>
    <value>11</value>
    <value>22</value>
    <value>33</value>
    </list>
    </property>
    <property name="map">
    <map>
    <entry>
    <key>
    <value>zs</value>
    </key>
    <value>张三</value>
    </entry>
    <entry>
    <key>
    <value>ls</value>
    </key>
    <value>李四</value>
    </entry>
    <entry>
    <key>
    <value>ww</value>
    </key>
    <value>王五</value>
    </entry>
    </map>
    </property>
    <property name="properties">
    <props>
    <prop key="a2">222</prop>
    </props>
    </property>
     
    </bean>


    6. 针对项目,配置文件路径的2种写法
    ApplicationContext 

    String path = "applicationContext.xml";(独自开发)

    String path = "classpath:applicationContext-*.xml";//src(分模块开发  多人开发)
     

    最近整理出了有关大数据,微服务,分布式,Java,Python,Web前端,产品运营,交互等1.7T的学习资料,有视频教程,源码,课件,工具,面试题等等。这里将珍藏多年的资源免费分享给各位小伙伴们,领取地址:https://blog.csdn.net/qq_42914528/article/details/83210719

    展开全文
  • 19.SpringBoot的搭建

    2020-07-14 22:20:04
    1、Spring的优缺点 1.1 优点 (1)开源,轻量级,非侵入式的一站式框架,简化企业级应用开发。 (2)控制反转(IOC),依赖注入(DI)降低了组件之间的耦合性,实现了软件各层之间的解耦。 (3)面向切面(AOP),利用它可以很...

    19. SpringBoot的搭建

    1、Spring的优缺点

    1.1 优点

    (1)开源,轻量级,非侵入式的一站式框架,简化企业级应用开发。

    (2)控制反转(IOC),依赖注入(DI)降低了组件之间的耦合性,实现了软件各层之间的解耦。

    (3)面向切面(AOP),利用它可以很容易实现一些拦截,如事务控制等。

    (4)spring对于主流的应用框架提供了很好的支持,例如mybatis。

    (5)spring提供有自己的mvc实现。

    1.2 缺点

    虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。虽然spring引入了注解功能,但是仍然需要编写大量的模板化配置文件.

    项目的jar依赖管理也是一件耗时耗力的事情,在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。

    1.3 SpringBoot解决问题

    SpringBoot对上述Spring的缺点进行的改善和优化,基于约定优于配置的思想.可以让开发人员不必在配置与逻辑业务之间进行思维的切换,全身心的投入到逻辑业务的代码编写中,从而大大提高了开发的效率,一定程度上缩短了项目周期。

    2、SpringBoot的概述

    2.1 概述

    Spring Boot是由Pivotal团队提供的在spring框架基础之上二次开发的框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。

    该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域成为领导者。

    Spring Boot就是对各种框架的整合,让他们集成在一起更加简单,它做了那些没有它你自己也会去做的Spring Bean配置。你不用再写这些样板配置了,可以专注于应用程序的逻辑.

    Spring Boot你只需要“run”就可以非常轻易的构建独立的、生产级别的spring应用。

    我们为spring平台和第三方依赖库提供了一种固定化的使用方式,使你能非常轻松的开始开发你的应用程序。大部分Spring Boot应用只需要很少的配置。

    2.2 SpringBoot的特点

    (1)创建独立的spring应用程序

    (2)直接内嵌tomcat、jetty和undertow(不需要打包成war包部署)

    (3)提供了固定化的“starter”配置,以简化构建配置

    (4)尽可能的自动配置spring和第三方库

    (5)提供产品级的功能,如:安全指标、运行状况监测和外部化配置等

    (6)绝对不会生成代码,并且不需要XML配置

    2.3 SpringBoot的核心功能

    起步依赖

    起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

    自动配置

    Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。

    3、搭建SpringBoot环境

    (1)Maven 下载 SpringBoot 依赖的jar包

    <!-- spring-boot web启动器 -->
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-web</artifactId>
    		<version>2.2.2.RELEASE</version>
    	</dependency>
    	
    <!-- 配置springboot内置tomcat环境 -->
    	<dependency>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-tomcat</artifactId>
    		<version>2.2.2.RELEASE</version>
    	</dependency>	
    

    (2)编写入口程序main函数

    SpringBoot 通过java的注解的形式启动,就像javaSE程序一样,通过main函数入口。

    package com.company.springboot03;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Springboot03Application {
        public static void main(String[] args) {
            SpringApplication.run(Springboot03Application.class, args);
        }
    }
    

    (3)编写配置文件 application.yml

    #内置服务器的配置
    server:
      port: 9999
    
    #spring的配置(配置spring视图解析器和数据源配置)
    spring:
      mvc:
        view:
          prefix: /WEB-INF/jsp/
          suffix: .jsp
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/shop?characterEncoding=utf-8&serverTimezone=GMT
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
        platform: mysql
        type: com.alibaba.druid.pool.DruidDataSource
        initialSize: 5
        minIdle: 5
        maxActive: 20
    

    (4)配置springboot热部署

    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-devtools</artifactId>
    	<version>2.2.2.RELEASE</version>
    </dependency>
    

    以后修改代码之后就不用每次执行main函数启动工程.

    (5)配置SpringBoot支持jsp

    <dependency>
    	<groupId>org.apache.tomcat.embed</groupId>
    	<artifactId>tomcat-embed-jasper</artifactId>
    	<version>9.0.22</version>
    </dependency>
    

    配置视图解析器

    spring:
      mvc:
        view:
          prefix: /WEB-INF/jsp/
          suffix: .jsp
    

    (6)SpringBoot集成JDBC

    导入jdbc包

        <!-- jdbc -->
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-jdbc</artifactId>
          <version>2.2.2.RELEASE</version>
        </dependency>
    

    导入mysql驱动包

        <!-- mysql-connector-java -->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.20</version>
        </dependency>
    

    (7)配置数据源信息

    导入阿里数据源

    <!-- 阿里数据源 -->
    	<dependency>
    	  <groupId>com.alibaba</groupId>
    	  <artifactId>druid</artifactId>
    	  <version>1.1.10</version>
    	</dependency>
    

    在yml文件注册阿里数据库连接池

    spring:
      datasource:
        url: jdbc:mysql://127.0.0.1:3306/shop?characterEncoding=utf-8&serverTimezone=GMT
        username: root
        password: 123456
        driver-class-name: com.mysql.cj.jdbc.Driver
        platform: mysql
        type: com.alibaba.druid.pool.DruidDataSource
        initialSize: 5
        minIdle: 5
        maxActive: 20
    

    (8)编写配置Druid的监控

    DruidDataSourceConfig.java

    package com.company.springBootPro.util;
    
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.sql.DataSource;
    
    import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.boot.web.servlet.ServletRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import com.alibaba.druid.support.http.StatViewServlet;
    import com.alibaba.druid.support.http.WebStatFilter;
    //spring自动扫描加载此类
    @Configuration
    public class DruidDataSourceConfig {
    
    	    @Bean
    		@ConfigurationProperties(prefix = "spring.datasource")
    	    public DataSource druid() {
    	        return new DruidDataSource();
    	    }
    	 
    	    // 配置Druid的监控
    	    // 1、配置一个管理后台的Servlet
    	    @Bean
    	    public ServletRegistrationBean statViewServlet() {
    	        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
    	 
    	        Map<String, String> initParams = new HashMap<String, String>();
    	        // 监控页面登录用户名	 
    	        initParams.put("loginUsername", "admin");
    	 
    	        // 监控页面登录用户密码
    	        initParams.put("loginPassword", "123456");
    	 
    	        // ip白名单(没有配置或者为空,则允许所有访问)
    	        initParams.put("allow", "");
    	 
    	        // ip黑名单(如果某个ip同时存在,deny优先于allow)
    	        initParams.put("deny", "");
    	        bean.setInitParameters(initParams);
    	        return bean;
    	    }
    	 
    	    // 2、配置一个web监控的filter
    	    @Bean
    	    public FilterRegistrationBean webStatFilter() {
    	        FilterRegistrationBean bean = new FilterRegistrationBean();
    	        bean.setFilter(new WebStatFilter());
    	 
    	        Map<String, String> initParams = new HashMap<String, String>();
    	 
    	        // 不拦截的静态资源
    	        initParams.put("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");
    	        bean.setInitParameters(initParams);
    	 
    	        // 拦截所有的请求
    	        bean.setUrlPatterns(Arrays.asList("/*"));
    	        return bean;
    	    }
    }
    

    (9)集成Mybatis

    导入springboot集成mybatis环境的jar包

     <dependency>
    		<groupId>org.mybatis.spring.boot</groupId>
    		<artifactId>mybatis-spring-boot-starter</artifactId>
    	    <version>2.1.1</version>
    </dependency>
    

    在application.yml中配置mybatis信息

    mybatis:
      mapper-locations: classpath:mapper/*Mapper.xml             #映射文件
      type-aliases-package: com.company.springBootPro.bean       #别名
      configuration:
        cache-enabled: true                                        #二级缓存
        map-underscore-to-camel-case: true                         #java驼峰与数据库下划线对应转换
    

    application.yml中配置控制台输出sql脚本

    # 配置控制台输出sql脚本
    logging:
      level:
        com:
          company:
            springBootPro:
              dao: TRACE
    

    在Springboot03Application.java主函数类的上面添加扫描mapper文件注解

    package com.company.springboot03;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    @MapperScan("com.company.springboot03.mapper")
    public class Springboot03Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Springboot03Application.class, args);
        }
    }
    

    (10)配置文件上传

    导入配置文件上传jar包

            <!-- 文件上传下载 -->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.3</version>
            </dependency>
    

    编写文件上传配置类

    package com.company.springboot03.util;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.multipart.commons.CommonsMultipartResolver;
    
    @Configuration
    public class MultipartConfig {
    
    	/**
         * 文件上传配置
         * @return
         */
        @Bean
        public CommonsMultipartResolver multipartConfigElement() {
        	CommonsMultipartResolver multipartresolver = new CommonsMultipartResolver();
        	multipartresolver.setMaxUploadSize(1024*1024*5);
        	multipartresolver.setDefaultEncoding("utf-8");
            return multipartresolver;
        }
    }
    

    (11)配置自定义拦截器

    编写拦截器类

    package com.company.springboot03.util;
    
    import com.company.springboot03.bean.User;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    public class LoginInterceptor implements HandlerInterceptor {
    
        /*
            方法:检测用户是否登录,若没有登录则跳转登录页
            当请求到达控制器之前被执行
    	   true--继续向下执行,到达下一个拦截器,或控制器
    	   false--不会继续向下执行
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            HttpSession session = request.getSession();
            User user = (User) session.getAttribute("user");
            if(user == null){
                response.sendRedirect(request.getContextPath()+"/demoCtl/toLogin");
                return false;
            }else{
                return true;
            }
        }
    
        /*
        控制器方法执行之后执行
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
        }
    
        /*
        整个请求结束后执行
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    
        }
    }
    

    配置自定义拦截器

    package com.company.springboot03.util;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    /**
     * 注册自定义拦截器
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer{
    
    	public void addInterceptors(InterceptorRegistry registry) {
    		InterceptorRegistration inter =  registry.addInterceptor(new LoginInterceptor());
    				inter.addPathPatterns("/**"); 					//拦截的路径
    				inter.excludePathPatterns("/demoCtl/toLogin");	//放行的路径
    	}
    }
    
    展开全文
  • springJDBC

    2020-08-02 17:39:35
    springJDBC

    1.JDBC

    JDBC技术
    全写为 java database connectivity
    翻译为 Java访问数据库的解决方案

    技术出现原因
    希望以相同的方式实现访问不同的数据库
    以实现与具体数据库无关的Java操作

    JDBC定义一套标准的接口,即访问数据库API
    不同的数据库厂商根据各自数据库的特点去实现接口
    从而得到Java程序访问

    JDBC接口:
    DriverManager:驱动管理类
    Connection:连接接口
    Statement:语句对象
    PreparedStatement:语句对象
    CallableStatement:调用存储过程语句对象
    ResutSet:结果集接口

    JDBC工作过程:
    1)加载驱动创建连接
    2)创建语句对象
    3)执行SQL语句
    4)处理结果集
    5)关闭资源

    1.1spring+JDBC

    前提准备
    数据库:mysq数据库
    开发工具:eclipse
    数据库中表:
    create table t_table(
    id int ,
    username varchar(30)
    )
    insert into t_table values(1,“aaa”);
    insert into t_table values(2,“bbb”);
    insert into t_table values(3,“ccc”);
    insert into t_table values(4,“ddd”);

    引入jar包
    mysql-connector-java-5.1.8-bin.jar
    spring-core-4.3.8.RELEASE.jar
    spring-beans-4.3.8.RELEASE.jar
    spring-context-4.3.8.RELEASE.jar
    commons-logging.jar
    spring-expression-4.3.8.RELEASE.jar
    spring-aop-4.3.8.RELEASE.jar

    ①新建Java项目
    直接使用Java代码表示为

    		//1.建立数据库连接
    		Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
    		//2.创建语句对象
    		PreparedStatement ps = con.prepareStatement("select * from t_table");
    		//3.执行sql语句
    		ResultSet rs = ps.executeQuery();
    		List<Table> tables = new ArrayList<Table>();
    		Table table = null;
    		//4.处理结果集
    		while (rs.next()) {
    			table = new Table(rs.getInt("id"), rs.getString("username"));
    			tables.add(table);
    		}
    		for (Table t : tables) {
    			System.out.println(t);
    		}
    		//5.关闭连接
    		rs.close();
    		ps.close();
    		con.close();
    

    如果使用spring,要类的加载交给容器处理
    所以DriverManager这个类交给容器,其它的类则不用
    而DriverManager中需要注入的参数是数据库连接地址、用户名和密码
    但该类本身并无构造器初始化参数和setter方法
    所以在Java中新建一个工具类获取参数,然后返回Connection对象

    外部配置文件 db.properties
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/test
    username=root
    password=root

    spring配置文件

    <context:component-scan base-package="com.ds"/>
    <util:properties id="db" location="classpath:db.properties" />  	
    <bean id="con" class="com.ds.util.DBUtil">
    	<property name="classname" value="#{db.driver}"/>
    	<property name="url" value="#{db.url}"/>
    	<property name="username" value="#{db.username}"/>
    	<property name="password" value="#{db.password}"/>	
    </bean>	
    

    DBUtil类

    private String classname;
    	private String url;
    	private String username;
    	private String password;
    
    	public String getClassname() {
    		return classname;
    	}
    
    	public void setClassname(String classname) {
    		this.classname = classname;
    	}
    
    	public String getUrl() {
    		return url;
    	}
    
    	public void setUrl(String url) {
    		this.url = url;
    	}
    
    	public String getUsername() {
    		return username;
    	}
    
    	public void setUsername(String username) {
    		this.username = username;
    	}
    
    	public String getPassword() {
    		return password;
    	}
    
    	public void setPassword(String password) {
    		this.password = password;
    	}
    
    	public Connection getConnection() {
    
    		try {
    			try {
    				Class.forName(classname);
    			} catch (ClassNotFoundException e) {
    				e.printStackTrace();
    			}
    			return DriverManager.getConnection(url, password, username);
    		} catch (SQLException e) {
    			e.printStackTrace();
    		}
    		return null;
    
    	}
    

    测试类

    	// spring+JDBC
    	@Test
    	public void test1() throws SQLException {
    		ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
    		DBUtil db = ac.getBean("con", DBUtil.class);
    		Connection con = db.getConnection();
    		PreparedStatement ps = con.prepareStatement("select * from t_table");
    		ResultSet rs = ps.executeQuery();
    		List<Table> tables = new ArrayList<Table>();
    		Table table = null;
    		while (rs.next()) {
    			table = new Table(rs.getInt("id"), rs.getString("username"));
    			tables.add(table);
    		}
    		for (Table t : tables) {
    			System.out.println(t);
    		}
    		rs.close();
    		ps.close();
    		con.close();
    	}
    

    测试结果

    Table [id=1, Username=aaa]
    Table [id=2, Username=bbb]
    Table [id=3, Username=ccc]
    Table [id=4, Username=ddd]

    这里只是把数据库连接基本类交给容器管理
    理想情况下只需要调用容器中数据库连接类,并输入查询语句,便可以返回结果

    1.2Spring对JDBC整合支持

    Spring对DAO data access object 提供哪些支持
    1)Spring对DAO异常提供统一处理
    2)Spring对DAO编写提供支持的抽象类
    3)减少DAO编码量,提高编程效率

    Spring对于DAO异常的支持
    Spring把特定某种技术的异常,如SQLException,
    统一转换为自己的异常,把异常进行封装
    异常以DataAccessException为父类
    它封装了原始的异常对象,不会丢失原始的错误信息

    DataAccessException继承于RuntimeException,是非检查异常
    把检查异常变成非检查异常,不需要再增加try catch语句块
    不会因为没有处理异常而出现编译错误,异常必须要处理可以用拦截器统一处理

    Spring对DAO编写支持
    Spring为了便于以一种一致的方式使用各种数据库访问技术,
    如JDBC、SpringJDBC、MyBatis、Hiibernate
    Spring提供一套抽象的DAO类,通过DAO类提供的方法
    可以获取数据库访问技术相关的数据源和其他配置相关信息

    jdbcTemplate:封装常用的JDBC操作方法
    jdbcDaoSupport:JDBC数据库访问对象的基类
    HibernateTemplate:封装常用Hibernate方法
    HibernateDaoSupport:Hibernate数据库访问对象的基类

    jdbcDaoSupport
    利用JDBC技术编写DAO的父类。通过此类提供的方法可便于获取Connection和jdbcTempate
    jdbcDaoSupport使用是需要注入一个DataSource
    jdbcTemplate:封装了链接获取以及连接释放等工作
    从而简化我们对JDBC的使用,避免忘记关闭连接等错误

    如何编写DAO组件
    基于Springjdbc技术编写DAO组件可以采用以下两种方式
    1)DAO继承jdbcDaoSupport,通过getJdbcTempate方法获取JdbcTemplate对象
    需要在DAO实现类中注入一个Dataource对象来完成JdbcTemplate的实例化
    @Autowired
    public void setDs(DataSource ds) {//容器中有BasicDataSource
    super.setDataSource(ds);
    }

    @Autowired
    public void setJT(JdbcTemplate jt) {
    super.setJdbcTemplate(jt);
    }
    或直接在bean中注入给父类
    <bean id=“deptDao” class=“com.ds.dao.DeptDao”>
    <property name=“dataSource” ref=“ds”/>
    </bean>

    Java类中代码

    public List<Dept> findAll() {
    		String sql = "select * from dept";
    		return this.getJdbcTemplate().query(sql, new DeptRowMapper());
    	}
    
    	class DeptRowMapper implements RowMapper<Dept> {
    		@Override
    		public Dept mapRow(ResultSet rs, int rowNum) throws SQLException {
    			return new Dept(rs.getInt("deptno"), rs.getString("dname"));
    		}
    	}
    
    

    2)DAO不继承JdbcDaoSupport,在spring的容器中配置一个JdbcTemplate的Bean
    然后注入给DAO组件,

    spring配置文件

    	<!--外部数据库数据文件-->
    	<util:properties id="db" location="classpath:db.properties"/>
    	 
    	<!--建立数据库连接--> 
    	<bean id="ds" class="org.apache.commons.dbcp2.BasicDataSource">
    		<property name="driverClassName" value="#{db.driver}"/>
    		<property name="url" value="#{db.url}"/>
    		<property name="username" value="#{db.username}"/>
    		<property name="password" value="#{db.password}"/>
    	</bean> 
    	 
    	<!-- 定义JDBCtemplate --> 
    	<bean class="org.springframework.jdbc.core.JdbcTemplate">
    		<property name="dataSource" ref="ds"/>
    	</bean>			
    	 
    	<context:component-scan base-package="com.ds"/>
    

    java类中代码

    	@Autowired
    	private JdbcTemplate jt;
    	
    	//查询
    	public List<Dept> findAll() {
    		return jt.query("select * from dept", new DeptRowMapper());
    	}
    	
    	//条件查询
    	public Dept findById(int deptno) {
    		return jt.queryForObject("select * from dept where deptno=?", new Object[] { deptno }, new DeptRowMapper());
    	}
    	
    	//增加
    	public void save(Dept dept) {
    		jt.update("insert into dept values(?,?)", dept.getDeptno(), dept.getDname());
    	}
    	
    	//更新
    	public void update(Dept dept) {
    		jt.update("update dept set dname=? where deptno=?", dept.getDname(), dept.getDeptno());
    	}
    
    	//删除
    	public void delete(int deptno) {
    		jt.update("delete from dept where deptno=?", deptno);
    	}
    
    	//结果集映射对象
    	class DeptRowMapper implements RowMapper<Dept> {
    		@Override
    		public Dept mapRow(ResultSet rs, int rowNum) throws SQLException {
    			return new Dept(rs.getInt("deptno"), rs.getString("dname"));
    		}
    	}
    
    展开全文
  • 部分答案可能有错,看到有问题麻烦提醒我修改,谢谢 ---------------------------------------------------------20191218第一次更新--------------------------------------------- 1.Jdk和Jre 的区别 ...
  • 1、javascript视频教程 链接: https://pan.baidu.com/s/1slYX3Ff 密码: jn92 2、JPA视频教程 链接: https://pan.baidu.com/s/1c3QkLQ4 密码: 8f8v 3、马士兵hibernate视频教程 链接: ...
  • 转:Java面试题

    2018-07-24 22:19:54
    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。 2、说说&...都可以用作逻辑与的运算符,表示...
  • Spring框架介绍及使用

    2018-03-17 10:49:54
    Spring框架—控制反转(IOC) 1 Spring框架概述 1.1 什么是Spring 1.2 Spring的优点 1.3 Spring的体系结构 2 入门案例:(IoC) 2.1导入jar包 2.2目标类 2.3 配置文件 2.4测试 3 入门案例:DI 3.1 目标类...
  • 目录 1、Spring概述 ...②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得...
  • Spring全家桶

    2019-05-27 22:24:24
    Spring框架自诞生以来一直备受开发者青睐,有人亲切的称之为:Spring 全家桶。它包括SpringMVC、SpringBoot、Spring Cloud、Spring Cloud Dataflow等解决方案。 很多研发人员把spring看作心目中最好的java项目,...
  • Spring深入理解

    2020-07-02 18:00:20
    在学习Spring之前首先来看一张图,通过对于这张图的理解进入我们需要学习的Java框架Spring。 这张图上展示了一个基于SSH,B/S结构的单体Java应用的搭建过程,首先通过浏览器进入到Filter拦截器,进入到Structs...
  • spring框架学习(一)

    2014-03-07 22:51:23
    1,什么是spring框架 spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。     2,架构...
  • Spring Cloud 是一套完整的微服务解决方案,基于 Spring Boot 框架,准确的说,它不是一个框架,而是一个大的容器,它将市面上较好的微服务框架集成进来,从而简化了开发者的代码量。 本课程由浅入深带领大家一步步...
  • 初识Spring Boot框架

    2019-06-20 22:35:31
    前面的铺垫文章已经连着写了六篇了,主要是介绍了Spring和SpringMVC框架,小伙伴们在学习的过程中大概也发现了这两个框架需要我们手动配置的地方非常多,不过做JavaEE开发的小伙伴们肯定也听说过“约定大于配置”...
  • Spring Cloud Bus 将分布式的节点和轻量的消息代理连接起来。这可以用于广播配置文件的更改或者其他的管理工作。一个关键的思想就是,消息总线可以为微服务做监控,也可以作为应用程序之间相互通讯。本文要讲述的是...
  • 本文出自方志朋的博客 错过了这一篇,你可能再也学...Spring Boot做为下一代 web 框架,Spring Cloud 作为最新最火的微服务的翘楚,你还有什么理由拒绝。赶快上船吧,老船长带你飞。终章不是最后一篇,它是一个...
  • 以前框架使用quartz框架执行定时调度问题、老大说这配置太麻烦、每个调度都需要多加在spring的配置中、能不能减少配置的量从而提高开发效率、最近看了看spring的 scheduled的使用注解的方式进行调度、感觉很方便、...
1 2 3 4 5 ... 20
收藏数 1,381,640
精华内容 552,656
关键字:

spring