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从入门到精通视频教程

    千人学习 2018-10-22 21:38:05
    理解并掌握 Spring 中 IOC、DI、AOP 等核心概念 理解 Spring 整合 Struts2 的基本原理
  • Spring-全面详解(学习总结)

    万次阅读 多人点赞 2020-07-30 10:23:17
    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框架介绍及使用

    万次阅读 多人点赞 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 目标类...

    Spring框架—控制反转(IOC)

    1 Spring框架概述

    1.1 什么是Spring

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。Spring的核心是控制反转(IoC)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。

    1.2 Spring的优点
    • 方便解耦,简化开发 (高内聚低耦合)
      Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
      spring工厂是用于生成bean
    • AOP编程的支持
      Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
    • 声明式事务的支持
      只需要通过配置就可以完成对事务的管理,而无需手动编程
    • 方便程序的测试
      Spring对Junit4支持,可以通过注解方便的测试Spring程序
    • 方便集成各种优秀框架
      Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
    • 降低JavaEE API的使用难度
      Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
    1.3 Spring的体系结构

    这里写图片描述

    2 入门案例:(IoC)

    2.1导入jar包
    • 4 + 1 : 4个核心(beans、core、context、expression) + 1个依赖(commons-loggins…jar)
      这里写图片描述
      这里写图片描述
    2.2目标类
    • 提供UserService接口和实现类
    • 获得UserService实现类的实例
      之前开发中,直接new一个对象即可。学习spring之后,将由Spring创建对象实例–> IoC 控制反转(Inverse of Control)
      之后需要实例对象时,从spring工厂(容器)中获得,需要将实现类的全限定名称配置到xml文件中
    public interface UserService {
        public void addUser();
    }
    public class UserServiceImpl implements UserService {
        @Override
        public void addUser() {
            System.out.println("a_ico add user");
        }
    }
    2.3 配置文件
    • 位置:任意,开发中一般在classpath下(src)
    • 名称:任意,开发中常用applicationContext.xml
    • 内容:添加schema约束
      约束文件位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\ xsd-config.html
    <?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">
        <!-- 配置service 
            <bean> 配置需要创建的对象
                id :用于之后从spring容器获得实例时使用的
                class :需要创建实例的全限定类名
        -->
        <bean id="userServiceId" class="com.itheima.a_ioc.UserServiceImpl"></bean>
    </beans>
    2.4测试
       @Test
        public void demo02(){
            //从spring容器获得
            //1 获得容器
            String xmlPath = "com/itheima/a_ioc/beans.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
            //2获得内容 --不需要自己new,都是从spring容器获得
            UserService userService = (UserService) applicationContext.getBean("userServiceId");
            userService.addUser();  

    3 入门案例:DI

    • 例如:

      class BookServiceImpl{
          //之前开发:接口 = 实现类  (service和dao耦合)
          //private BookDao bookDao = new BookDaoImpl();
          //spring之后 (解耦:service实现类使用dao接口,不知道具体的实现类)
          private BookDao bookDao;
          setter方法
      }
      模拟spring执行过程
      创建service实例:BookService bookService = new BookServiceImpl()     -->IoC  <bean>
      创建dao实例:BookDao bookDao = new BookDaoImple()                -->IoC
      将dao设置给service:bookService.setBookDao(bookDao);             -->DI   <property>
      
    3.1 目标类
    • 创建BookService接口和实现类
    • 创建BookDao接口和实现类
    • 将dao和service配置 xml文件
    • 使用api测试
    3.2 dao
    public interface BookDao {
        public void save();
    }
    public class BookDaoImpl implements BookDao {
    
        @Override
        public void save() {
            System.out.println("di  add book");
        }
    }
    3.3 service
    public interface BookService {
    
        public abstract void addBook();
    
    }
    public class BookServiceImpl implements BookService {
    
        // 方式1:之前,接口=实现类
    //  private BookDao bookDao = new BookDaoImpl();
        // 方式2:接口 + setter
        private BookDao bookDao;
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
    
        @Override
        public void addBook(){
            this.bookDao.save();
        }
    
    }
    3.4 配置文件
    <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">
        <!-- 
        模拟spring执行过程
            创建service实例:BookService bookService = new BookServiceImpl() IoC  <bean>
            创建dao实例:BookDao bookDao = new BookDaoImpl()         IoC
            将dao设置给service:bookService.setBookDao(bookDao);     DI   <property>
    
            <property> 用于进行属性注入
                name: bean的属性名,通过setter方法获得
                    setBookDao ##> BookDao  ##> bookDao
                ref :另一个bean的id值的引用
         -->
    
        <!-- 创建service -->
        <bean id="bookServiceId" class="com.itheima.b_di.BookServiceImpl">
            <property name="bookDao" ref="bookDaoId"></property>
        </bean>
    
        <!-- 创建dao实例 -->
        <bean id="bookDaoId" class="com.itheima.b_di.BookDaoImpl"></bean>
    
    
    </beans>
    3.5 测试
        @Test
        public void demo01(){
            //从spring容器获得
            String xmlPath = "com/itheima/b_di/beans.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
            BookService bookService = (BookService) applicationContext.getBean("bookServiceId");    
            bookService.addBook();
        }

    4 依赖注入装配Bean 基于xml

    4.1属性依赖注入
    • 依赖注入方式:手动装配 和 自动装配
      • 手动装配:一般进行配置信息都采用手动
        基于xml装配:构造方法、setter方法
      • 基于注解装配:
    4.1.1 构造方法

    目标类

    public class User {
    
        private Integer uid;
        private String username;
        private Integer age;
    
        public User(Integer uid, String username) {
            super();
            this.uid = uid;
            this.username = username;
        }
    
        public User(String username, Integer age) {
            super();
            this.username = username;
            this.age = age;
        }
    

    spring配置

        <!-- 构造方法注入 
            * <constructor-arg> 用于配置构造方法一个参数argument
                name :参数的名称
                value:设置普通数据
                ref:引用数据,一般是另一个bean id值
    
                index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。
                type :确定参数类型
            例如:使用名称name
                <constructor-arg name="username" value="jack"></constructor-arg>
                <constructor-arg name="age" value="18"></constructor-arg>
            例如2:【类型type 和  索引 index】
                <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
                <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
        -->
        <bean id="userId" class="com.itheima.f_xml.a_constructor.User" >
            <constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
            <constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
        </bean>
    4.1.2 setter方法
    <!-- setter方法注入 
            * 普通数据 
                <property name="" value="值">
                等效
                <property name="">
                    <value>值
            * 引用数据
                <property name="" ref="另一个bean">
                等效
                <property name="">
                    <ref bean="另一个bean"/>
    
        -->
        <bean id="personId" class="com.itheima.f_xml.b_setter.Person">
            <property name="pname" value="阳志"></property>
            <property name="age">
                <value>1234</value>
            </property>
    
            <property name="homeAddr" ref="homeAddrId"></property>
            <property name="companyAddr">
                <ref bean="companyAddrId"/>
            </property>
        </bean>
    
        <bean id="homeAddrId" class="com.itheima.f_xml.b_setter.Address">
            <property name="addr" value="阜南"></property>
            <property name="tel" value="911"></property>
        </bean>
        <bean id="companyAddrId" class="com.itheima.f_xml.b_setter.Address">
            <property name="addr" value="北京八宝山"></property>
            <property name="tel" value="120"></property>
        </bean>
    4.2 集合依赖注入
    <!-- 
            集合的注入都是给<property>添加子标签
                数组:<array>
                List:<list>
                Set:<set>
                Map:<map> ,map存放k/v 键值对,使用<entry>描述
                Properties:<props>  <prop key=""></prop>  【】
    
            普通数据:<value>
            引用数据:<ref>
        -->
        <bean id="collDataId" class="com.itheima.f_xml.e_coll.CollData" >
            <property name="arrayData">
                <array>
                    <value>DS</value>
                    <value>DZD</value>
                    <value>屌丝</value>
                    <value>屌中屌</value>
                </array>
            </property>
    
            <property name="listData">
                <list>
                    <value>于嵩楠</value>
                    <value>曾卫</value>
                    <value>杨煜</value>
                    <value>曾小贤</value>
                </list>
            </property>
    
            <property name="setData">
                <set>
                    <value>停封</value>
                    <value>薄纸</value>
                    <value>关系</value>
                </set>
            </property>
    
            <property name="mapData">
                <map>
                    <entry key="jack" value="杰克"></entry>
                    <entry>
                        <key><value>rose</value></key>
                        <value>肉丝</value>
                    </entry>
                </map>
            </property>
    
            <property name="propsData">
                <props>
                    <prop key="高富帅"></prop>
                    <prop key="白富美"></prop>
                    <prop key="男屌丝"></prop>
                </props>
            </property>
        </bean>

    5 依赖注入装配Bean 基于注解

    • 注解:就是一个类,使用@注解名称
    • 开发中:使用注解 取代 xml配置文件。
      1.@Component取代<bean class="">
      @Component("id") 取代 <bean id="" class="">
      2.web开发,提供3个@Component注解衍生注解(功能一样)取代
      @Repository :dao层
      @Service:service层
      @Controller:web层
      3.依赖注入,给私有字段设值,也可以给setter方法设值

      • 普通值:@Value(" ")
      • 引用值:
        方式1:按照【类型】注入
        @Autowired
        方式2:按照【名称】注入1
        @Autowired
        @Qualifier("名称")
        方式3:按照【名称】注入2
        @Resource("名称")

        4.生命周期
        初始化:@PostConstruct
        销毁:@PreDestroy

        5.作用域
        @Scope("prototype") 多例
        注解使用前提,添加命名空间,让spring扫描含有注解类
        
        <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">
        <!-- 组件扫描,扫描含有注解的类 -->
        <context:component-scan base-package="com.itheima.g_annotation.a_ioc"></context:component-scan>
        </beans>
        

    Spring框架—面向切面编程(AOP)

    1 什么是AOP

    • 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
    • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
    • 经典应用:事务管理、性能监视、安全检查、缓存 、日志等
    • Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
    • AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入

    2 AOP实现原理

    • aop底层将采用代理机制进行实现。
    • 接口 + 实现类 :spring采用 jdk 的动态代理Proxy。
    • 实现类:spring 采用 cglib字节码增强。

    3 AOP术语【掌握】

    1.target:目标类,需要被代理的类。例如:UserService
    2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
    3.PointCut 切入点:已经被增强的连接点。例如:addUser()
    4.advice 通知/增强,增强代码。例如:after、before
    5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
    6.proxy 代理类
    7. Aspect(切面): 是切入点pointcut和通知advice的结合
    一个线是一个特殊的面。
    一个切入点和一个通知,组成成一个特殊的面。
    这里写图片描述

    4 AOP实现方式

    4.1手动方式

    4.1.1JDK动态代理
    • JDK动态代理 对“装饰者”设计模式 简化。使用前提:必须有接口

    1.目标类:接口 + 实现类

    public interface UserService {
        public void addUser();
        public void updateUser();
        public void deleteUser();
    }

    2.切面类:用于存通知 MyAspect

    public class MyAspect { 
        public void before(){
            System.out.println("鸡首");
        }   
        public void after(){
            System.out.println("牛后");
        }
    }

    3.工厂类:编写工厂生成代理

    public class MyBeanFactory {
    
        public static UserService createService(){
            //1 目标类
            final UserService userService = new UserServiceImpl();
            //2切面类
            final MyAspect myAspect = new MyAspect();
            /* 3 代理类:将目标类(切入点)和 切面类(通知) 结合 --> 切面
             *  Proxy.newProxyInstance
             *      参数1:loader ,类加载器,动态代理类 运行时创建,任何类都需要类加载器将其加载到内存。
             *          一般情况:当前类.class.getClassLoader();
             *                  目标类实例.getClass().get...
             *      参数2:Class[] interfaces 代理类需要实现的所有接口
             *          方式1:目标类实例.getClass().getInterfaces()  ;注意:只能获得自己接口,不能获得父元素接口
             *          方式2:new Class[]{UserService.class}   
             *          例如:jdbc 驱动  --> DriverManager  获得接口 Connection
             *      参数3:InvocationHandler  处理类,接口,必须进行实现类,一般采用匿名内部
             *          提供 invoke 方法,代理类的每一个方法执行时,都将调用一次invoke
             *              参数31:Object proxy :代理对象
             *              参数32:Method method : 代理对象当前执行的方法的描述对象(反射)
             *                  执行方法名:method.getName()
             *                  执行方法:method.invoke(对象,实际参数)
             *              参数33:Object[] args :方法实际参数
             * 
             */
            UserService proxService = (UserService)Proxy.newProxyInstance(
                                    MyBeanFactory.class.getClassLoader(), 
                                    userService.getClass().getInterfaces(), 
                                    new InvocationHandler() {
    
                                        @Override
                                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                                            //前执行
                                            myAspect.before();
    
                                            //执行目标类的方法
                                            Object obj = method.invoke(userService, args);
    
                                            //后执行
                                            myAspect.after();
    
                                            return obj;
                                        }
                                    });
    
            return proxService;
        }
    
    }

    4.测试

    @Test
        public void demo01(){
            UserService userService = MyBeanFactory.createService();
            userService.addUser();
            userService.updateUser();
            userService.deleteUser();
        }
    4.1.2 CGLIB字节码增强
    • 没有接口,只有实现类。
    • 采用字节码增强框架 cglib,在运行时 创建目标类的子类,从而对目标类进行增强。

    工厂类

    public class MyBeanFactory {
    
        public static UserServiceImpl createService(){
            //1 目标类
            final UserServiceImpl userService = new UserServiceImpl();
            //2切面类
            final MyAspect myAspect = new MyAspect();
            // 3.代理类 ,采用cglib,底层创建目标类的子类
            //3.1 核心类
            Enhancer enhancer = new Enhancer();
            //3.2 确定父类
            enhancer.setSuperclass(userService.getClass());
            /* 3.3 设置回调函数 , MethodInterceptor接口 等效 jdk InvocationHandler接口
             *  intercept() 等效 jdk  invoke()
             *      参数1、参数2、参数3:以invoke一样
             *      参数4:methodProxy 方法的代理
             *      
             * 
             */
            enhancer.setCallback(new MethodInterceptor(){
    
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    
                    //前
                    myAspect.before();
    
                    //执行目标类的方法
                    Object obj = method.invoke(userService, args);
                    // * 执行代理类的父类 ,执行目标类 (目标类和代理类 父子关系)
                    methodProxy.invokeSuper(proxy, args);
    
                    //后
                    myAspect.after();
    
                    return obj;
                }
            });
            //3.4 创建代理
            UserServiceImpl proxService = (UserServiceImpl) enhancer.create();
    
            return proxService;
        }
    
    }

    4.2半自动

    • 让spring 创建代理对象,从spring容器中手动的获取代理对象
    4.2.1目标类
    public interface UserService {
        public void addUser();
        public void updateUser();
        public void deleteUser();
    }
    4.2.2切面类
    /**
     * 切面类中确定通知,需要实现不同接口,接口就是规范,从而就确定方法名称。
     * * 采用“环绕通知” MethodInterceptor
     *
     */
    public class MyAspect implements MethodInterceptor {
    
        @Override
        public Object invoke(MethodInvocation mi) throws Throwable {
    
            System.out.println("前3");
    
            //手动执行目标方法
            Object obj = mi.proceed();
    
            System.out.println("后3");
            return obj;
        }
    }
    4.2.3Spring 配置
    <!-- 1 创建目标类 -->
        <bean id="userServiceId" class="com.itheima.b_factory_bean.UserServiceImpl"></bean>
        <!-- 2 创建切面类 -->
        <bean id="myAspectId" class="com.itheima.b_factory_bean.MyAspect"></bean>
    
        <!-- 3 创建代理类 
            * 使用工厂bean FactoryBean ,底层调用 getObject() 返回特殊bean
            * ProxyFactoryBean 用于创建代理工厂bean,生成特殊代理对象
                interfaces : 确定接口们
                    通过<array>可以设置多个值
                    只有一个值时,value=""
                target : 确定目标类
                interceptorNames : 通知 切面类的名称,类型String[],如果设置一个值 value=""
                optimize :强制使用cglib
                    <property name="optimize" value="true"></property>
            底层机制
                如果目标类有接口,采用jdk动态代理
                如果没有接口,采用cglib 字节码增强
                如果声明 optimize = true ,无论是否有接口,都采用cglib
    
        -->
        <bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="interfaces" value="com.itheima.b_factory_bean.UserService"></property>
            <property name="target" ref="userServiceId"></property>
            <property name="interceptorNames" value="myAspectId"></property>
        </bean>
    4.2.4 测试
        @Test
        public void demo01(){
            String xmlPath = "com/itheima/b_factory_bean/beans.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
    
            //获得代理类
            UserService userService = (UserService) applicationContext.getBean("proxyServiceId");
            userService.addUser();
            userService.updateUser();
            userService.deleteUser();
        }

    4.3全自动

    • 从spring容器获得目标类,如果配置aop,spring将自动生成代理。
    4.3.1 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"
           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">
        <!-- 1 创建目标类 -->
        <bean id="userServiceId" class="com.itheima.c_spring_aop.UserServiceImpl"></bean>
        <!-- 2 创建切面类(通知) -->
        <bean id="myAspectId" class="com.itheima.c_spring_aop.MyAspect"></bean>
        <!-- 3 aop编程 
            3.1 导入命名空间
            3.2 使用 <aop:config>进行配置
                    proxy-target-class="true" 声明时使用cglib代理
                <aop:pointcut> 切入点 ,从目标对象获得具体方法
                <aop:advisor> 特殊的切面,只有一个通知 和 一个切入点
                    advice-ref 通知引用
                    pointcut-ref 切入点引用
            3.3 切入点表达式
                execution(* com.itheima.c_spring_aop.*.*(..))
                选择方法         返回值任意   包             类名任意   方法名任意   参数任意
    
        -->
        <aop:config proxy-target-class="true">
            <aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/>
            <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
        </aop:config>
    </beans>
    4.3.2 测试
        @Test
        public void demo01(){
            String xmlPath = "com/itheima/c_spring_aop/beans.xml";
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
    
            //获得目标类
            UserService userService = (UserService) applicationContext.getBean("userServiceId");
            userService.addUser();
            userService.updateUser();
            userService.deleteUser();
        }
    展开全文
  • Spring框架总结【无比详细】

    万次阅读 多人点赞 2020-07-21 17:14:45
    以下内容是我在初学spring时候做的笔记,当时是把比较放在了备忘录里面,如今把笔记重整到csdn上,为了复习也为了分析给大家,笔记写的算比较完整,回看自己做的还是有点羞涩。如有错误之处,欢迎指正,当我日后更...

    以下内容是我在初学spring时候做的笔记,当时是把比较放在了备忘录里面,如今把笔记重整到csdn上,为了复习也为了分析给大家,笔记写的算比较完整,回看自己做的还是有点羞涩。如有错误之处,欢迎指正,当我日后更强大的时候,我会不断的对内容进行补充和完善。当然学习也就是这么一个过程,学习-实践-总结-实践-总结...   转载请申明原文地址,希望大家支持,谢谢。

     

    1、IOC和DI

    IOC: 控制反转
    即控制权的转移,将我们创建对象的方式反转了,以前对象的创建是由我们开发人员自己维护,包括依赖关系也是自己注入。使用了spring之后,对象的创建以及依赖关系可以由spring完成创建以及注入,反转控制就是反转了对象的创建方式,从我们自己创建反转给了程序创建(spring)

    DI:  Dependency Injection  依赖注入
    spring这个容器中,替你管理着一系列的类,前提是你需要将这些类交给spring容器进行管理,然后在你需要的时候,不是自己去定义,而是直接向spring容器索取,当spring容器知道你的需求之后,就会去它所管理的组件中进行查找,然后直接给你所需要的组件.
    实现IOC思想需要DI做支持
    注入方式:   1.set方式注入    2.构造方法注入   3.字段注入
    注入类型:   1.值类型注入      2.引用类型注入

     

    好处: 

    1.降低组件之间的耦合度,实现软件各层之间的解耦.


    2.可以使容器提供众多服务如事务管理消息服务处理等等。当我们使用容器管理事务时,开发人员就不需要手工 控制事务,也不需要处理复杂的事务传播

    
3.容器提供单例模式支持,开发人员不需要自己编写实现代码.

    
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能


    5.容器提供众多的辅佐类,使这些类可以加快应用的开发.如jdbcTemplate HibernateTemplate
     

     

    2.applicationContext & BeanFactory区别

    BeanFactory接口
    (1) spring的原始接口,针对原始接口的实现类功能较为单一
    (2)BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象


    ApplicationContext接口
    (1)每次容器启动时就会创建容器中配置的所有对象
    (2)提供了更多功能
    (3)从类路径下加载配置文件: ClassPathXmlApplicationContext
    从硬盘的绝对路径下加载配置文件:FileSystemXmlApplication

     

    3.spring配置详解

    3.1、元素属性

        bean元素:使用该元素描述需要spring容器管理对象
        name属性:给被管理的对象起个名字,获得对象时getBean("name值")
        class属性:被管理对象的完整类名
        id属性:与name属性一模一样,名称不可重复,不能使用特殊字符

     

    name和id之间的一些注意点:
    1、配置两个相同的 id 或者 name 都不能通过。
    2、如果既配置了 id ,也配置了 name ,则两个都生效。如果id和name都没有指定,则用类全名作为name,如<bean class="com.stamen.BeanLifeCycleImpl">,则你可以通过getBean("com.stamen.BeanLifeCycleImpl")返回该实例。
    3、如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 相同的时候, 则两个冲突,配置文件生效。
          如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 不相同的时候, 则两个不冲突,都能够生效。

     

    3.2、bean元素进阶(  scope属性   生命周期属性)—————单例多例


    (1)scope属性
        (1)singleton   默认值   
    单例对象   :被标识为单例的对象在spring容器中只会存在一个实例
        (2)prototype    
    多例原型:被标识为多例的对象,每次在获得才会被创建,每次创建都是新的对象
        (3)request
    Web环境下,对象与request生命周期一致    
        (4)session
    Web环境下,对象与session生命周期一致
    总结:绝大多数情况下,使用单例singleton(默认值),但是在与struts整合时候,务必要用prototype多例,因为struts2在每次请求都会创建一个新的Action,若为单例,在多请求情况下,每个请求找找spring拿的都是同一个action。

     

    (2)生命周期属性(了解)———初始化和销毁
        (1)配置一个方法作为生命周期初始化方法,spring会在对象创建之后立刻调用 init-method
        (2)配置一个方法作为生命周期的销毁方法,spring容器在关闭并销毁所有容器中的对象之前调用destory-method
        <bean init-method=“init”  destory-method=“destory”></bean>        对应注解为@PostConstruct

        <bean name=“hello” class=“完整类名”></bean>                                 对应注解为@PreDestory


    (3)模块化配置,即分模块配置(导入其他spring配置文件)
    <beans>
        <import resource = “spring配置文件的全路径名” />
    </beans>

     

    3.3、spring三种对象的创建方式

    (1)空参数构造(重要)

    (2)静态工厂创建(调用静态方法创建)
    调用UserFactory类的静态createUser方法创建名为user的对象,放入容器
     

    <bean name="user" class="cn.itcats.UserFactory" factory-method="createUser"></bean>


    (3)实例工厂创建(调用非静态方法创建)——需要配置两个bean,因为无法通过类名调用非静态方法
     

    <bean name="user2" factory-bean="userFactory" factory-method="createUser"></bean>
    
    <bean name=“userFactory” class=“cn.itcats.UserFactory”></bean>
    

     

    3.4、spring注入方式

    (1)set方式注入(重点)————值类型用value注入    引用类型用ref注入

     

    (2)构造方法注入

     

    函数注入
    (3)p名称空间注入———实际上set注入,spring特有,为了简化<property>写法

       1、applicationContext.xml中<beans>标签头部导入p命名空间

    xmlns:p="http://www.springframework.org/schema/p"

       2、书写格式:值类型注入——  p:属性名="值"      引用类型注入——  p:属性名-ref="引用的<bean> name属性"

           把Run类中的name属性值设置为haha,age属性设置为20,引用属性hello引用<bean name="hello" class="..."></bean>

    <bean name="run2" class="cn.itcats.thread.Run" p:name="haha" p:age="20" p:hello-ref="hello"></bean>

     

     (4)spel注入: spring Expression Language spring表达式语言

    <bean name="runSpel" class="cn.itcats.thread.Run">
        <!-- 取bean标签中name为"user"中property为"name"中的value值 --!>
        <property name="name" value="#{user.name}"></property>
    </bean>

    SpEL特性:(1)、使用Bean的ID来引用Bean;(2)、调用方法和访问对象的属性;(3)、对值进行算术、关系和逻辑运算;(4)、正则表达式匹配;(5)、集合操作

    关于spel   https://www.cnblogs.com/goodcheap/p/6490896.html

     

    复杂类型注入

        1.array数组的注入

     

    2.list集合的注入

     

       3.map集合的注入

     

        4.properties的注入

     

    4、防止创建多个applicationContext取值/并指定记载spring配置文件的位置——web.xml

       1、需要导入包spring-web
       2、在web.xml中配置监听器

     

    5、使用注解方式代替配置文件(官方推荐使用注解)

         1.在applicationContext.xml中书写指定扫描注解

       

          2.在类中书写Component

    注意:假如不写括号内的值(即name或id),默认使用类名首字母小写作为搜索,为什么意思呢?

    比如Student类中使用了@Component   没有书写括号和值,那么默认搜索id或name为student。

     

         3.指定对象的作用范围Scope

             声明Student类对象为多例       下面是对singleton和prototype的一些补充

    • singleton作用域:当把一个Bean定义设置为singleton作用域是,Spring IoC容器中只会存在一个共享的Bean实例,并且所有对Bean的请求,只要id与该Bean定义相匹配,则只会返回该Bean的同一实例。值得强调的是singleton作用域是Spring中的缺省作用域。

    • prototype作用域:prototype作用域的Bean会导致在每次对该Bean请求(将其注入到另一个Bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的Bean实例。根据经验,对有状态的Bean应使用prototype作用域,而对无状态的Bean则应该使用singleton作用域。对于具有prototype作用域的Bean,有一点很重要,即Spring不能对该Bean的整个生命周期负责。具有prototype作用域的Bean创建后交由调用者负责销毁对象回收资源。简单的说:

    • singleton 只有一个实例,也即是单例模式

    • prototype访问一次创建一个实例,相当于new。

     

        4.值类型的注入

                                                                                           实际通过反射field赋值

     

                                                                                           实际通过set方式赋值

     

         5.引用类型的注入

    面试题: @AutoWired和@Resource的区别?

    @AutoWired默认以类型进行查找,@Resource默认以名称进行查找

    @AutoWired(required=false)    +   @Qualifier("user")    ==   @Resource(name="user")

    其中@Resource注解是jdk1.6后才有的

     

     

        6.创建与销毁方法

     

         7.spring整合junit测试(spring创建容器)

         @RunWith(SpringJUnit4ClassRunner.class)
         @ContextConfiguration("classpath:applicationContext.xml")    

     

        6、spring中AOP名词解释

    JoinPoint(连接点):目标对象中,所有可以增强的方法,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。


    Pointcut(切入点):目标对象中,已经被增强的方法。调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法。


    Advice(通知/增强) :增强方法的代码、想要的功能。


    Target(目标对象):被代理对象,被通知的对象,被增强的类对象。


    Weaving(织入):将通知应用到连接点形成切入点的过程


    Proxy(代理):将通知织入到目标对象之后形成的代理对象


    aspect(切面):切入点+通知————通知(Advice)说明了干什么的内容(即方法体代码)和什么时候干(什么时候通过方法名中的before,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),切点表达式等定义。

    虽然现在都用Maven项目构建,但是不能忘记,使用aop需要用到的包:spring-aop + spring-aspects     + springsource.org.aopalliance  + springsource.org.aspectj.weaver 

    关于AOP看一个小例子:

     1、准备目标对象(被代理对象,被通知的对象,被增强的类对象)

     

          2、准备通知(被增强方法的代码,想要实现功能的方法代码)

     

           3、配置 applicationContext.xml
                1.导入aop(约束)命名空间
                2.配置目标对象
                3.配置通知对象
                4.配置将通知织入目标对象

     

            4、测试

    总结:通知的几种类型
        1.前置通知———目标方法运行之前调用
        2.后置通知———目标方法运行之后调用(如果出现异常不调用)
        3.环绕通知———目标方法之前和之后都调用
        4.异常拦截通知———如果出现异常,就会调用
        5.后置通知———目标方法运行之后调用(无论是否出现异常都会调用)

     

         7、spring中的aop使用注解配置

           1、applicationContext.xml中配置目标对象,通知对象,开启使用注解完成织入

     

         2、@Aspect注解代表该类是个通知类,书写切点表达式@Pointcut("execution(返回值 全类名.方法名(参数))")

    注意环绕通知需要这么写:

    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    	    //环绕方法执行前
                //proceedingJoinPoint.proceed();表示对拦截的方法进行放行
                //若注释proceedingJoinPoint.proceed()则不会执行被AOP匹配的方法
    			proceedingJoinPoint.proceed();
                //环绕方法执行后
    	}

    AOP注解解析:

    @Before 前置通知(Before advice) :在某连接点(JoinPoint)——核心代码(类或者方法)之前执行的通知,但这个通知不能阻止连接点前的执行。为啥不能阻止线程进入核心代码呢?因为@Before注解的方法入参不能传ProceedingJoinPoint,而只能传入JoinPoint。要知道从aop走到核心代码就是通过调用ProceedingJionPoint的proceed()方法。而JoinPoint没有这个方法。 
    这里牵扯区别这两个类:Proceedingjoinpoint 继承了 JoinPoint 。是在JoinPoint的基础上暴露出 proceed 这个方法。proceed很重要,这个是aop代理链执行的方法。暴露出这个方法,就能支持 aop:around 这种切面(而其他的几种切面只需要用到JoinPoint,这跟切面类型有关), 能决定是否走代理链还是走自己拦截的其他逻辑。建议看一下 JdkDynamicAopProxy的invoke方法,了解一下代理链的执行原理。这样你就能明白 proceed方法的重要性。

    @After 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

    @AfterReturning 返回后通知(After return advice) :在某连接点正常完成后执行的通知,不包括抛出异常的情况。

    @Around 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。这时aop的最重要的,最常用的注解。用这个注解的方法入参传的是ProceedingJionPoint pjp,可以决定当前线程能否进入核心方法中——通过调用pjp.proceed();

    @AfterThrowing 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。

     

          8、spring整合jdbc

          spring中提供了一个可以操作数据库的对象,对象封装了jdbc技术  ————JDBCTemplate JDBC模板对象,而JdbcDaoSupport则对JdbcTemplate进行了封装,所以要操作JdbcTemplate,或只需要继承JdbcDaoSupport即可。

          

     

             依赖关系配置:

     

                   测试:

                     

         9、spring中的aop事务

    事务的四大基本特性:

    事物的概述

    原子性(Atomicity

      原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

    一致性(Consistency

      一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

      拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管AB之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

    隔离性(Isolation

      隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

      即要达到这么一种效果:对于任意两个并发的事务T1T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

      关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。

    持久性(Durability

      持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

      例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

     

    关于事务的隔离级别我之前发布了一篇文章https://blog.csdn.net/itcats_cn/article/details/81487466

     

    spring中事务的分类:

    spring中事务可以分为编程式事务控制和声明式事务控制。

    编程式事务控制

           自己手动控制事务,就叫做编程式事务控制。

           Jdbc代码:

                  Conn.setAutoCommit(false);  // 设置手动控制事务

           Hibernate代码:

                  Session.beginTransaction();    // 开启一个事务

           【细粒度的事务控制: 可以对指定的方法、指定的方法的某几行添加事务控制】

           (比较灵活,但开发起来比较繁琐: 每次都要开启、提交、回滚.)

     

    声明式事务控制

           Spring提供了对事务的管理, 这个就叫声明式事务管理。

           Spring提供了对事务控制的实现。用户如果想用Spring的声明式事务管理,只需要在配置文件中配置即可; 不想使用时直接移除配置。这个实现了对事务控制的最大程度的解耦

           Spring声明式事务管理,核心实现就是基于Aop

           【粗粒度的事务控制: 只能给整个方法应用事务,不可以对方法的某几行应用事务。】

           (因为aop拦截的是方法。)

     

           Spring声明式事务管理器类:

                  Jdbc技术:DataSourceTransactionManager

                  Hibernate技术:HibernateTransactionManager

    有一点需要注意的:若为编程式事务控制,则开启事务后一定要手动释放(提交或回滚),否则长期占用内存,有可能报事务异常

     

    spring封装了事务管理的代码(打开,提交,回滚事务)
    事务操作对象,因为在不同平台,操作事务的代码各不相同.spring提供了一个接口
    ————— PlatformTransactionManager 接口
    ————— 在不同平台,实现不同的接口即可
    ————— 注意:在spring中玩事务管理.最为核心的对象就是TransactionManager对象

     

    spring管理事务的属性介绍
            (1)事务的隔离级别
            (2)是否只读
            (3)事务的传播行为
     

    配置事务的核心管理器,它封装了所有事务,依赖于连接池(DataSourceTransactionManager)

     

    xml中配置通知

    配置将通知织入目标

    10、spring中aop管理事务 注解使用步骤

    在需要管理的方法或者类中声明配置事务管理

    @Transactional(isolation=Isolation.REPEATABLE_READ,readOnly=false,propagation=Propagation.REQUIRED)

     

    展开全文
  • 什么是spring,它能够做什么?

    万次阅读 多人点赞 2018-11-03 09:49:23
    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

    展开全文
  • Spring (一 ) 概述与介绍

    万次阅读 多人点赞 2020-03-13 23:32:10
    目录 1、Spring概述 ...②Spring为简化企业级开发而生,使用Spring开发可以将Bean对象,Dao组件对象,Service组件对象等交给Spring容器来管理,这样使得很多复杂的代码在Spring中开发却变得...
  • Spring是什么?

    万次阅读 多人点赞 2018-05-29 10:20:09
    Spring是什么? Spring是一个开源的轻量级的Java开发框架。 2.Spring能帮我们做什么? 简化应用程序的开发。 3.简化应用程序开发体现在哪些方面? ①IOC容器 Java思想是面向对象的开发,一个应用程序是由一组...
  • Spring

    2020-10-24 12:32:28
    1-1 spring简介 01-spring简介-框架的概念 02-spring简介-spring概念与体系结构 03-spring发展史与优势 1-2 IoC 04-IoC简介-控制翻转概念(IoC) 05-IoC入门案例-入门案例制作 06-IoC配置-bean的基本配置 07-IoC配置...
  • 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是什么?干什么的?怎么用?

    万次阅读 多人点赞 2020-05-08 17:26:29
    spring是什么? 1:是一个轻量级的开源框架,是为解决企业应用开发的复杂性而创建的; 2:是一个三层架构,也为J2EE应用程序开发提供集成的框架; Web层:Spring MVC; 业务层 :Spring的IoC; 持久层 :...
  • Spring Boot和Spring Cloud的区别

    万次阅读 多人点赞 2018-12-13 16:04:42
    1、Spring boot 是 Spring 的一套快速配置脚手架,可以基于spring boot 快速开发单个微服务;Spring Cloud是一个基于Spring Boot实现的云应用开发工具; 2、Spring boot专注于快速、方便集成的单个个体,Spring ...
  • Spring Boot与Spring的区别

    万次阅读 2017-06-07 17:48:19
    Spring Boot是最近这几年才火起来的,那么它到底与Spring有啥区别呢?想了解区别,其实就是Spring Boot提供了哪些特征: Spring Boot可以建立独立的Spring应用程序; 内嵌了如Tomcat,Jetty和Undertow 这样的容器,...
  • spring-cloud-dependencies管理的相关依赖

    万次阅读 2020-05-03 08:36:35
    spring-boot-parent或spring-boot-dependencies管理的依赖 spring-cloud-dependencies 版本Hoxton.SR3管理依赖的版本号如下: <properties> <spring-cloud-kubernetes.version>1.1.2.RELEASE<...
  • SpringCloud教程(上)

    万次阅读 多人点赞 2020-10-20 13:46:18
    SpringCloud入门教程,SpringCloud详细教程。SpringCloud是一系列框架的有序集合。如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。本文主要...
  • SpringCloud详细教程(下)

    万次阅读 多人点赞 2020-08-12 09:03:56
    SpringCloud详细教程,springcloud实战教程。Springcloud微服务教程(上)的姊妹篇:介绍了其它SpringCloud组件。
  • 推荐几个Spring Cloud学习资料

    万次阅读 多人点赞 2019-06-20 22:40:32
    研究Spring Cloud也有一段时间了,手头上有一点收集的资料,分享给小伙伴们学习。 博客 1.跟我学Spring Cloud 2.周立|Spring Cloud 3.Spring Cloud基础教程(强烈推荐) 4.Spring Cloud系列文章 5.forezp|史...
  • 浅析Spring boot与Spring cloud 之间的关系

    万次阅读 多人点赞 2018-05-17 16:28:43
    浅析Spring boot与Spring cloud 之间的关系 2018-05-15 18:16:10有些童鞋刚接触这块 ,理解不是很深刻会经常问道这样类似的问题,下面我就简单讲解一下Spring boot与Spring cloud 之间的关系!Spring boot 是 ...
  • 但是,当把自己的一个项目导入IDEA之后,Event Log提示“Unmapped Spring configuration files found.Please configure Spring facet.”  这个提示不影响工程正常运行,但是,作为一个强迫症~~每天看到这个提示...
  • Spring各个版本源码下载地址

    万次阅读 2018-01-04 14:21:47
    https://github.com/spring-projects/spring-framework/tags
1 2 3 4 5 ... 20
收藏数 1,486,976
精华内容 594,790
关键字:

spring