spring (转载老师讲义,博主只图查看方便)

SpringFramework

一、介绍

Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。Spring 是轻量级的框架,其基础版本只有 2 MB 左右的大小。Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。

1、Spring 框架主要的好处

  1. Spring 可以使开发人员使用 POJOs 开发企业级的应用程序。只使用 POJOs 的好处是你不需要一个 EJB 容器产品,比如一个应用程序服务器,但是你可以选择使用一个健壮的 servlet 容器,比如 Tomcat 或者一些商业产品。

  2. Spring 在一个单元模式中是有组织的。即使包和类的数量非常大,你只要担心你需要的,而其它的就可以忽略了。

  3. Spring 不会让你白费力气做重复工作,它真正的利用了一些现有的技术,像ORM 框架、日志框架、JEE、Quartz 和 JDK 计时器,其他视图技术。

  4. 测试一个用 Spring 编写的应用程序很容易,因为环境相关的代码被移动到这个框架中。此外,通过使用 JavaBean-style POJOs,它在使用依赖注入注入测试数据时变得更容易。

  5. Spring 的 web 框架是一个设计良好的 web MVC 框架,它为比如 Structs 或者其他工程上的或者不怎么受欢迎的 web 框架提供了一个很好的供替代的选择。

  6. Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。

  7. 轻量级的 IOC 容器往往是轻量级的,例如,特别是当与 EJB 容器相比的时候。这有利于在内存和 CPU 资源有限的计算机上开发和部署应用程序。

  8. Spring提供了一致的事务管理接口,可向下扩展到(使用一个单一的数据库,例如)本地事务并扩展到全局事务(例如,使用 JTA)。

2、spring 两大核心特性

2.1、IOC依赖注入(DI)

Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(IoC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。

当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能的独立于其他的 Java 类来增加这些类可重用可能性,当进行单元测试时,可以使它们独立于其他类进行测试。依赖注入(或者有时被称为配线)有助于将这些类粘合在一起,并且在同一时间让它们保持独立。

到底什么是依赖注入?让我们将这两个词分开来看一看。这里将依赖关系部分转化为两个类之间的关联。例如,类 A 依赖于类 B。现在,让我们看一看第二部分,注入。所有这一切都意味着类 B 将通过 IoC 被注入到类 A 中。

依赖注入可以以向构造函数传递参数的方式发生,或者通过使用 setter 方法 post-construction。由于依赖注入是 Spring 框架的核心部分,所以我将在一个单独的章节中利用很好的例子去解释这一概念。

2.2、面向方面的程序设计(AOP):

Spring 框架的一个关键组件是面向方面的程序设计(AOP)框架。一个程序中跨越多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各种各样常见的很好的关于方面的例子,比如日志记录、声明性事务、安全性,和缓存等等。

在 OOP 中模块化的关键单元是类,而在 AOP 中模块化的关键单元是方面。AOP 帮助你将横切关注点从它们所影响的对象中分离出来,然而依赖注入帮助你将你的应用程序对象从彼此中分离出来。

Spring 框架的 AOP 模块提供了面向方面的程序设计实现,可以定义诸如方法拦截器和切入点等,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。我将在一个独立的章节中讨论更多关于 Spring AOP 的概念。

3、Spring 框架结构

          3.1、体系结构图

Spring 有可能成为所有企业应用程序的一站式服务点,然而,Spring 是模块化的,允许你挑选和选择适用于你的模块,不必要把剩余部分也引入。Spring 框架提供约 20 个模块,可以根据应用程序的要求来使用。

  • spring-core模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。

  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。

  • context模块建立在由corebeans 模块的基础上建立起来的,它以一种类似于JNDI注册的方式访问对象。Context模块继承自Bean模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过Servelet容器)等功能。Context模块也支持Java EE的功能,比如EJB、JMX和远程调用等。ApplicationContext接口是Context模块的焦点。spring-context-support提供了对第三方库集成到Spring上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。

  • spring-expression模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。

  • JDBC 模块提供了JDBC抽象层,它消除了冗长的JDBC编码和对数据库供应商特定错误代码的解析。

  • ORM 模块提供了对流行的对象关系映射API的集成,包括JPA、JDO和Hibernate等。通过此模块可以让这些ORM框架和spring的其它功能整合,比如前面提及的事务管理。

  • OXM 模块提供了对OXM实现的支持,比如JAXB、Castor、XML Beans、JiBX、XStream等。

  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从Spring 4.1开始,集成了spring-messaging模块。。

  • 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写beginTransaction()、commit()、rollback()等事务管理方法,声明式事务是通过注解或配置由spring自动处理,编程式事务粒度更细)

  • Web 模块提供面向web的基本功能和面向web的应用上下文,比如多部分(multipart)文件上传功能、使用Servlet监听器初始化IoC容器等。它还包括HTTP客户端以及Spring远程调用中与web相关的部分。。

  • Web-MVC 模块为web应用提供了模型视图控制(MVC)和REST Web服务的实现。Spring的MVC框架可以使领域模型代码和web表单完全地分离,且可以与Spring框架的其它所有功能进行集成。

  • Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。

  • Web-Portlet 模块提供了用于Portlet环境的MVC实现,并反映了spring-webmvc模块的功能。

  • AOP 模块提供了面向方面的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。

  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

  • Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

  • Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

  • 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

二、IOC&DI

1、IoC 容器

Spring 容器是 Spring 框架的核心。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans。

Spring通过阅读配置元数据提供的指令,容器知道对哪些对象进行实例化,配置和组装。配置元数据可以通过 XML,Java 注释或 Java 代码来表示。下图是 Spring 如何工作的高级视图。 Spring IoC 容器利用 Java 的 POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。

2、Spring 各种IOC 容器

容器类型-接口 实现类 描述
ApplicationContext 容器 FileSystemXmlApplicationContext 该容器从 XML 文件中加载已被定义的 bean;你需要提供给构造器 XML 文件的完整路径
  ClassPathXmlApplicationContext 该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
  WebXmlApplicationContext 该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean

三、基于XML配置

1、注册一个Bean到容器

开发流程:

①创建工程 并在pom文件中添加依赖

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

②创建pojo类 Car.java

package com.xingxue.spring.domain;
​
public class Car  {
    
    private  String  brand; //品牌
    private  String  carName; //型号名称
    private  String  carType; // 类型
    private  Double  price // 售价
    
    //此处省略...sets and  gets
}

③创建spring的配置文件 applicationContext.xml 位于 classpath 下

<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">
    <!--注册向IOC中注册一个Bean-->
    <bean name="mycar" class="com.xingxue.spring.domain.Car">
        <!--注入属性:底层调用set方法-->
        <property name="brand" value="宝马"/>
        <property name="carName" value="X5"/>
        <property name="carType" value="SUV"/>
        <property name="price" value="400000"/>
    </bean>
</beans>

④创建容器并测试

     @Test
    public  void test1(){
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object car=  ctx.getBean("mycar");
        System.out.println(car);
    }

2、bean 的作用域

当在 Spring 中定义一个 bean 时,你必须声明该 bean 的作用域的选项。例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype。同理,如果你想让 Spring 在每次需要时都返回同一个bean实例,你应该声明 bean 的作用域的属性为 singleton

作用域 描述
singleton 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session 一般用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境
   <bean name="mycar2" class="com.xingxue.spring.domain.Car" scope="prototype">
        <!--注入属性:底层调用set方法-->
        <property name="brand" value="宝马"/>
        <property name="carName" value="X5"/>
        <property name="carType" value="SUV"/>
        <property name="price" value="400000"/>
    </bean>

这里只讨论 singleton prototype ,其他三个需要在使用web环境下有效

3、bean 的生命周期

生命周期指bean床创建到初始化到销毁的一个过程,spring中可以监听到这个过程

    
   <bean name="mycar3" class="com.xingxue.spring.domain.Car" scope="prototype" 
        init-method="begin"    
        destroy-method="end">
        <!--注入属性:底层调用set方法-->
        <property name="brand" value="宝马"/>
        <property name="carName" value="X5"/>
        <property name="carType" value="SUV"/>
        <property name="price" value="400000"/>
    </bean>

init-method="begin" 监听bean初始化 begin为bean 中的一个方法

destroy-method="end" 监听bean销毁 end为bean 中的一个方法

4、依赖注入

当注册一个bean时,bean的属性需要赋值,为这些属性赋值就是为其依赖赋值,赋值的过程就是依赖注入的过程spring中有两种方式。

  • 属性set方法注入(调用Bean中提供的set方法)

           <!-- 向ioc容器中注册了一个bean -->
           <bean id="car"  class="com.xingxue.spring.pojo.Car" scope="prototype"
                 destroy-method="destory" init-method="init">
                <!--为bean属性赋值-->
                <property name="brand" value="宝马"/>
                <property name="carName" value="X5"/>
                <property name="type"  value="SUV" />
                <property name="price" value="500000"/>
           </bean>    
    ​
           <bean id="p1" class="com.xingxue.spring.pojo.Person">
                    <property name="name" value="谭仓龙"/>
                    <property name="age" value="24"/>
                    <property name="car" ref="car">    
           </bean>

    这里使用的是外部 bean, 如果只想用一次可以使用内部 bean

     <bean id="p1" class="com.xingxue.spring.pojo.Person">
                    <property name="name" value="谭仓龙"/>
                    <property name="age" value="24"/>
                    <!--<property name="car" ref="car">-->
                    <property name="car">
                          <bean class="com.xingxue.spring.pojo.Car">
                                   <property name="brand"  value="Audi"/>
                                   <property name="type" value="B级车"/>
                                   <property name="carName" value="a6l" />
                                   <property name="price" value="300000"/>
                          </bean>
                    </property>
     </bean>

    Spring中简单的数据类型 如 8大基本数据类型及其包装类和String 类型可以通过 value直接赋值,但如果是自定义的类型,需要使用 ref 引用赋值,或者使用内部bean赋值。


    List[数组] Set Map Properties 类型注入

    ①List

    <bean id="st" class="com.xingxue.spring.pojo.Student">
                <property name="name" value="王红"/>
                <property name="hobby">
                        <list>
                            <value>Maven 入门到精通</value>
                            <value>Mybatis</value>
                            <value>LOL</value>
                        </list>
                </property>
         </bean>

    ②Set

        <bean id="st2" class="com.xingxue.spring.pojo.Student">
            <property name="name" value="杨询"/>
            <property name="skills">
                  <set>
                      <ref bean="car"></ref>
                      <value>扔石头</value>
                      <value>打劫</value>
                  </set>
            </property>
        </bean>

    ③Map

        <bean id="st4" class="com.xingxue.spring.pojo.Student">
               <property name="name" value="李心浩"/>
               <property name="maps">
                     <map>
                           <entry key="m1" value="范冰冰"/>
                           <entry key="m2" value="成龙"/>
                           <entry key="m3" value="摩登兄弟"/>
                     </map>
               </property>
        </bean>

    ④Properties

     <bean id="st4" class="com.xingxue.spring.pojo.Student">
               <property name="name" value="李心浩"/>
               <property name="maps">
                     <map>
                           <entry key="m1" value="范冰冰"/>
                           <entry key="m2" value="成龙"/>
                           <entry key="m3" value="摩登兄弟"/>
                     </map>
               </property>
        </bean>

补充: 读取properties文件中的数据赋值给 javaBean的属性。

db.properties文件

user=root
password=admin
driver=com.mysql.jdbc.Driver
url=jdbc:mysql:///xxx

dbutis.java

public class DButils {
        private  String  user;
        private  String  password;
        private  String  url;
        private  String  driver;
        // 此处省略 get set方法
}

spring 配置文件

    <!--  注册一个bean 读取外部propeties 文件  -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" >
          <property name="location" value="db.properties"/>
    </bean>
    <bean class="com.xingxue.spring.pojo.DButils" id="dbutis">
            <property name="user" value="${user}"/>
            <property name="url" value="${url}"/>
            <property name="password" value="${password}"/>
            <property name="driver" value="${driver}"/>
    </bean>

${ } :spring EL 表达式

  • 构造器注入

public class CarServiceImpl implements CarService {
    //注入如 Dao 对象
    CarDao  carDao;
​
    public  CarServiceImpl(CarDao carDao){
        this.carDao=carDao;
    }
​
    @Override
    public List<Car> list() throws Exception {
        System.out.println("服务层执行 调用Dao层........");
        return carDao.selectAll();
    }
}
 <bean class="com.xingxue.spring.dao.impl.CarDaoImpl" id="carDao"/>
​
 <bean class="com.xingxue.spring.service.impl.CarServiceImpl" id="carService">
        <constructor-arg name="carDao" ref="carDao"/>
 </bean>

5、自动装配

  • byType

        <bean class="com.xingxue.spring.pojo.Person" autowire="byType">
            <property name="name" value="赵浩"/>
            <property name="age" value="40"/>
        </bean>

    autowire="byType" : 开启自动装配,根据l类型装配,IOC 容器把选择类型一致的Bean注入,当有多个bean同时满足注入条件,可以使用 autowire-candidate="false" 禁用默认满足条件的bean(加了这个属性的bean放弃注入)

  • byName

        <bean class="com.xingxue.spring.pojo.Person" autowire="byName">
              <property name="name" value="赵浩"/>
             <property name="age" value="40"/>
        </bean>

    autowire="byName" : 开启自动装配,根据名字装配,IOC容器会把 现有Bean名字跟被装配属性名字一致Bean 自动注入

  • constructor

    <bean class="com.xingxue.spring.pojo.Person" autowire="constructor">
            <property name="name" value="赵浩"/>
            <property name="age" value="40"/>
     </bean>

和byType类似,根据构造器参数类型注入

  • no

    autowire="no" 就是不注入

四、基于注解配置

xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    <!--  包扫描 -->
    <context:component-scan base-package="com.xingxue.spring"/>
    <!--  开启注解配置-->
    <context:annotation-config/>
   
</beans>

java代码

控制器

@Controller
public class CarController {
     // 自动注入服务层依赖
     @Autowired
     private CarService carService;
​
     public  void  getAll() throws Exception{
          System.out.println("调用CarService");
          carService.list();
      }
      public void setCarService(CarService carService) {
        this.carService = carService;
      }
}

服务层

@Service
public class CarServiceImpl implements CarService {
    // 自动注入如 持久层 依赖
    @Autowired
    private  CarDao  carDao;
    @Override
    public List<Car> list() throws Exception {
        System.out.println("服务层执行 调用Dao层........");
        return carDao.selectAll();
    }
    public void setCarDao(CarDao carDao) {
        this.carDao = carDao;
    }
}

持久层

@Repository
public class CarDaoImpl implements CarDao {
    @Override
    public List<Car> selectAll() throws Exception {
        System.out.println("连接数据库查询到了全部数据..........");
        return  null;
    }
}

各种注解:

@Component : 通用注解,表示一个组件,没有业务含义

@Controller: 控制器层专门注解,表示控制器

@Service: 服务层注解,表示业务逻辑

@Repository:持久层注解,表示持久层

@Autowired:自动注入依赖

五、Aop编程

AOP面向方面,是一种编程思想,是对面向对象(OOP)的完善和补充,弥补了OOP横向切入编程能力,AOP的主要作用是把非业务逻辑代码和业务逻辑代码分离。用于处理 日志,事务,权限验证,数据校验等场景。SprinpAOP默认使用JDK对象代理,当被代理对象没有接口时使用cglib动态代理技术。

1、动态代理

动态代理:首先aop实现的底层技术就是代理技术,代理技术是一种软件设计模式,叫代理模式,代理模式分按用途分可以有很多种,但是按照创建方式分为,静态代理和动态代理,静态代理,要创建N个代理类,动态代理动态生成代理对象,无需手动创建代理类,JDK也提供了动态代理机制。

以下设计静态代理示例代码:

public class IGirl {
    public  void cook() ;
}
public class  SimpleGirl  implments IGirl{
    public  void cook() {
        System.out.println("做饭....");
    }
}
class  ProxyGirl implments  IGirl {
     private  Girl  relGril;
     public  ProxyGirl(Girl girl){
         this.relGril=girl;
     }
     public  void cookie(){
             System.out.println("买菜....");
              this.relGril.cook();
    }
}

以下是动态代理的示例代码:

public interface IFly {
         public void fly();
}
public class Birds  implements  IFly {
    @Override
    public void fly() {
        System.out.println("鸟儿飞........");
    }
}
public class Plane implements  IFly {
    @Override
    public void fly() {
        System.out.println("飞机飞..........");
    }
}
public class MyInvocationHandler implements InvocationHandler {
​
    //把被代理对对象传入
    private  IFly  relobj;
    public MyInvocationHandler(   IFly  obj  ){
          this.relobj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        System.out.println("----------- 前置 增强 ---------------");
        Object rs= null;
        try {
            //核心业务
            rs = method.invoke(relobj ,  args );
            System.out.println("----------返回 增强------------");
        } catch (Exception e) {
            System.out.println("----------异常 增强------------");
        }
        System.out.println("----------- 后置 增强 --------------");
        return rs;
    }
}

2、使用SpringAOP( 注解配置 )

① 引入依赖

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
    </dependency>

② 编写 切面

@Component
@Aspect
public class LogAspect {
      @Before("execution( * com.xingxue.spring.aop.SimpleCaculate.add(..) )")
      public  void  logBefore(JoinPoint joinPoint){
          System.out.println( "开始执行"+joinPoint.getSignature()+ System.currentTimeMillis() );
      }
​
      @After("execution(* com.xingxue.spring.aop.SimpleCaculate.sub(..))")
      public void logAfter( JoinPoint joinPoint ){
          System.out.println("结束执行"+joinPoint.getSignature()+ System.currentTimeMillis());
      }
}
​

③ 编写 接口和实现类

package com.xingxue.spring.aop;
/**
 * 计算器接口
 */
public interface Icaculate {
    public  int  add(int a, int b );
    public  int  sub(int a, int b);
}

编写 实现类

package com.xingxue.spring.aop;
import org.springframework.stereotype.Component;
/**
 * 计算器实现类
 */
@Component
public class SimpleCaculate implements  Icaculate {
    @Override
    public int add(int a, int b) {
        return a+b;
    }
    @Override
    public int sub(int a, int b) {
        return a-b;
    }
}

④ 配置xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
​
        <!--开启包扫描-->
        <context:component-scan base-package="com.xingxue.spring.aop"/>
        <!--开启注解配置-->
        <context:annotation-config/>
        <!-- 开启动态代理-->
        <aop:aspectj-autoproxy />
</beans>

⑤测试

     @Test
      public void test(){
         ApplicationContext  ctx = new ClassPathXmlApplicationContext("aop.xml");
             Icaculate  cc= ctx.getBean(Icaculate.class);
              cc.add(1,1);
              cc.sub(1,1);
      }

开始执行int com.xingxue.spring.aop.Icaculate.add(int,int)1536031653004结束执行int com.xingxue.spring.aop.Icaculate.sub(int,int)1536031653004

3、关于Aop的几个概念

  1. Aspect(切面):通常是一个类,里面可以定义切入点和通知

  2. JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用(方法执行前 抛异常 返回数据 )

  3. Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around

  4. Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式

  5. AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类

4、aop中的五种通知

      // @Before: 前置通知,目标方法运行前执行
      @Before("execution( * com.xingxue.spring.aop.SimpleCaculate.add(..) )")
      public  void  logBefore(JoinPoint point){
          System.out.println(new Date()+"开始执行"+ point.getSignature().getName()+"参数为:"+ Arrays.toString(point.getArgs()));
      }
    //  @ After:后置通知,目标方法无论执行成功与否,都会通知
    @After("execution( * com.xingxue.spring.aop.SimpleCaculate.add(..) )")
    public  void logAfter(JoinPoint point){
        System.out.println(new Date()+"结束执行"+ point.getSignature().getName()+"参数为:"+ Arrays.toString(point.getArgs()));
    }
    //  @AfterReturning:返回通知,目标方法执行没有异常,返回了数据,会通知
    @AfterReturning(value = "execution( * com.xingxue.spring.aop.SimpleCaculate.add(..) )", returning ="rs")
    public void  logAfterReturn( JoinPoint point ,int rs ){
        System.out.println(new Date()+"返回通知:"+ rs);
    }
    // @AfterThrowing : 异常通知,目标方法执行失败,抛出异常则通知
@AfterThrowing(value = "execution( * com.xingxue.spring.aop.SimpleCaculate.add(..) )", throwing ="ex")
    public void  logAfterReturn( JoinPoint point ,Exception ex ){
        System.out.println(new Date()+"异常通知:"+ ex);
    }
//   @Around : 环绕通知,是上述几个通知的总合,各种通知环绕目标方法周围
   @Around("execution( * com.xingxue.spring.aop.SimpleCaculate.add(..) )")
   public  Object  arround(ProceedingJoinPoint point ){
       Object rs=null;
        System.out.println("前置通知");
        try {
            rs  =  point.proceed( point.getArgs() );
            System.out.println("返回通知");
​
        } catch (Throwable throwable) {
            System.out.println("异常通知");
            throwable.printStackTrace();
        }
        System.out.println("后置后置");
        return  rs;
    }

JoinPoint :连接点,获得连接点信息,如方法签名,参数 等信息,ProceedingJoinPoint 也是连接点,但是只能是环绕通知使用。

5、切点表达式

1、切点表达式

  • 用于表示切入点的表达式, (scope) 包名.类名.方法名(参数类型,...)

  • scope: 方法访问权限: public private protected ,通常使用 * 表示任意

  • 包名:不解释,实际情况下可能是多级,如com.xingxue.service.impl ,通常简写 com.xingxue.. ; .. 表示省略多级

  • 类名:不解释,如 UserService 通常使用 * 表示任意类名 ,com.xingxue.service.*

  • 方法名:不解释,如save 通常使用 * 表示任意方法名,如 com.xingxue.service.UserService.*

  • 参数:不解释,如 int,int 通常使用 .. 表示任意多个参数 ,public com.xingxue.service.UserService.save(..)

  • 最终通常写为 : * com.xingxue.service . . * . * ( . . )

2、切入点函数

中心思想是重用切点表达式,把表达式跟函数进行绑定,函数不需要实现

@Pointcut(value ="execution( * com.xingxue.spring..*.*(..) )")
public static void beforePintcut(){
}
@Before(value = "beforePintcut()")
public  void  logBefore(JoinPoint point){
          System.out.println(new Date()+"开始执行"+ point.getSignature().getName()+"参数为:"+                              Arrays.toString(point.getArgs()));
}

跨类使用 切点

   @Before(value = "com.xingxue.spring.aop.LogAspect.beforePintcut()")
    public  void  numValidate(JoinPoint point){
        Object[]  args=  point.getArgs();
        if( Integer.parseInt(args[0].toString() )  >0 &&  Integer.parseInt(args[1].toString() )  >0   ){
            System.out.println("符合要求");
        }else{
            System.out.println("参数有误");
        }
    }

6、切面的优先级

同一个目标切点多个切面,可以配置优先级,跳转执行顺序 @Order(n) n越小优先级越高,反之越低。

@Component
@Aspect
@Order(2)
public class LogAspect {
    // 日志切面
}
@Component
@Aspect
@Order(1)
public class ValidateAspect {
    // 数据验证切面
}

7、集合log4j处理日志

log4j依赖

    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>

log4j配置文件(参考网上)

log4j.rootLogger=debug,stdout,info,debug,warn,error 
#console
log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
#info log
log4j.logger.info=info
log4j.appender.info=org.apache.log4j.DailyRollingFileAppender 
log4j.appender.info.DatePattern='_'yyyy-MM-dd'.log'
log4j.appender.info.File=d:/logs/log_info.log
log4j.appender.info.Append=true
log4j.appender.info.Threshold=INFO
log4j.appender.info.layout=org.apache.log4j.PatternLayout 
log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
  Logger logger = Logger.getLogger(LogAspect.class);
​
  logger.info("xxxx");

8、使用xml配置aop

      <!--注册bean-->
       <bean id="caculate" class="com.xingxue.spring.aopxml.SimpleCaculate"/>
      <!--注册切面-->
       <bean  id="log"  class="com.xingxue.spring.aopxml.LogAspect"/>
        <!-- aop 配置 -->
       <aop:config>
              <!--配置切点-->
              <aop:pointcut id="pointcut" expression="execution(*  com.xingxue.spring.aopxml..*.*(..))" />
              <!--配置切面  oder:优先级   ref:引用声明的切面-->
               <aop:aspect order="1" ref="log" >
                     <!--配置通知,method:切面中的方法   pointcut-ref:引用声明切点 -->
                    <aop:before method="logBefore" pointcut-ref="pointcut"/>
                    <aop:after method="logAfter" pointcut-ref="pointcut"/>
               </aop:aspect>
       </aop:config>

六、Spring-jdb支持

Spring 对jdbc 提供支持,简化jdbc开发流程,类似于Dbutils,使用Spring-jdbc 适用于简单的数据访问操作,当使用ORM框架对应当前系统比较麻烦的时候,可以采取spring-jdbc。spring-jdbc提供了一个操作数据的简单工具JdbcTemplate。

使用流程

① 添加依赖

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.46</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.9</version>
    </dependency>

② 数据库连接信息

#mysql connection information
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql:///mybatis
jdbc.driverClassName=com.mysql.jdbc.Driver

③ spring 配置

 
       <!-- 引入外部配置文件(自动注册 PropertyPlaceholderConfigurer Bean) -->
        <context:property-placeholder location="classpath*:db.properties"/>
       <!--配置数据源-->
       <bean  id="dataSource"  class="com.alibaba.druid.pool.DruidDataSource">
               <property name="username" value="${jdbc.user}"/>
               <property name="password" value="${jdbc.password}"/>
               <property name="url" value="${jdbc.url}"/>
               <property name="driverClassName" value="${jdbc.driverClassName}"/>
       </bean>
      <!-- 注册jdbctemplate -->
      <bean id="jdbcTemplate"  class="org.springframework.jdbc.core.JdbcTemplate">
             <property name="dataSource" ref="dataSource"/>
      </bean>
​
 
​

④测试

    ---------------------------查询多个对象---------------------------
    query(String sql , RowMapper  mapper , Object...args):List<T>
    说明:     sql:  执行的sql语句
            mapper:  映射规则RoMapper是接口,通常使用 BeanPropertyRowMapper 实现,作用是把字段转换到                    Bean的属性
              args:  可变参数,用于替换sql语句中的?,没有?可不填
    -----------------------------------------------------------------
    @Test
    public  void test(){
        JdbcTemplate tp = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        String sql = "select  *  from  tb_employee ";
        // BeanPropertyRowMapper: 查询字段映射到 对象属性
        List<EmpModel> list = tp.query(sql,  new BeanPropertyRowMapper<>(EmpModel.class) );
        System.out.println(list);
    }
    
   ---------------------------查询单个对象---------------------------
       queryForObject(String sql , RowMapper  mapper , Object...args):T
    说明:     sql:  执行的sql语句
            mapper:  映射规则RoMapper是接口,通常使用 BeanPropertyRowMapper 实现,作用是把字段转换到                    Bean的属性
              args:  可变参数,用于替换sql语句中的?没有?可不填
    ------------------------------------------------------------------
    //@Test
    public  void test3(){
        JdbcTemplate tp = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        String sql = "select  *  from  tb_employee where emp_no=? ";
        // BeanPropertyRowMapper: 查询字段映射到 对象属性
        EmpModel  model=  tp.queryForObject(sql,new BeanPropertyRowMapper<>(EmpModel.class),2);
        System.out.println(model);
    }
    
    ---------------------------查询某个字段---------------------------
    queryForObject(String sql , Class<T> cls , Object...args):T
    说明:     sql:  执行的sql语句
               cls:  Class 表示类类型,这里表示需要把查询的字段 转换成 什么类型返回
              args:  可变参数,用于替换sql语句中的?没有?可不填
    ------------------------------------------------------------------  
    @Test
    public  void test4(){
        JdbcTemplate tp = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        String sql = "select  count(*) from  tb_employee";
        Integer count=  tp.queryForObject(sql, Integer.class );
        System.out.println(count);
    }
​
    ---------------------------查询多行记录 返回List<Map>---------------------------
    queryForList(String sql ,Object...args):List<Map>
    说明:     sql:  执行的sql语句
              args:  可变参数,用于替换sql语句中的?没有?可不填
    -------------------------------------------------------------------------------
   @Test
    public  void test6(){
        JdbcTemplate tp = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        String sql ="select  *  from tb_employee e, tb_department  d  where e.dept_no = d.dept_no";
        List<Map<String, Object>> maps = tp.queryForList(sql);
        System.out.println(maps);
    }
​
    ---------------------------查询单行记录 返回Map---------------------------
    queryForMap(String sql ,Object...args):Map
    说明:     sql:  执行的sql语句
              args:  可变参数,用于替换sql语句中的?没有?可不填
    -------------------------------------------------------------------------
   @Test
    public  void test6(){
        JdbcTemplate tp = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        String sql ="select  *  from tb_employee e, tb_department  d  where e.dept_no = d.dept_no a                      nd e.emp_no=?";
        List<Map<String, Object>> maps = tp.queryForMap(sql,1);
        System.out.println(maps);
    }
​
 ---------------------------更新操作(insert  delete  update)-------------------------
    update(String sql , Object..args): int
       说明:  sql:  执行的sql语句
              args:  可变参数,用于替换sql语句中的?没有?可不填
 -------------------------------------------------------------------------------------
    @Test
    public  void test7(){
        JdbcTemplate tp = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        String sql ="insert into tb_employee values(?,?,?,?,?)";
        int row=  tp.update(sql,111,"小东","123323","重庆",11);
        System.out.println(row);
    }
    
​
​
------------------------批量更新操作(insert  delete  update)---------------------------
    batchUpdate(sql,params):int[]
       说明:  sql:  执行的sql语句
              args:  可变参数,用于替换sql语句中的?没有?可不填
    @Test
    public  void test8(){
        JdbcTemplate tp = (JdbcTemplate) ctx.getBean("jdbcTemplate");
        String sql ="insert into tb_employee values(?,?,?,?,?)";
        List<Object[]> params = new ArrayList<Object[]>();
        params.add(   new Object[]{222,"a","123232","aaaa",11  }    );
        params.add(   new Object[]{333,"a","123232","aaaa",11  }    );
        params.add(   new Object[]{444,"a","123232","aaaa",11  }    );
​
        int[] rows=  tp.batchUpdate(sql,params);
        System.out.println(Arrays.toString(rows));
    }
​

七、Spring事务管理

1、事务概念

事务(Transaction)是并发控制的单位,是用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。通过事务,数据库能将逻辑相关的一组操作绑定在一起,以便服务器保持数据的完整性。

2、事务特点

  1. 原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。

  2. 一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。

  3. 隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。

     隔离级别:  
    
                         读完未提交,读到被人没有提交的数据,产生脏读
    
                         读已提交,只能读到已经提交的数据 ,  Oracle采取这个级别,但会出现不可重复读  
    
                         可重复读 ,在同一个事务一个事务中,读取读取得到一致的效果,MySQL默认的隔离级别
    
                         序列化读, 当一个事务操作过程中,其他事务等待,序列化读会锁表,效率低,数据一致性高。
    
    
    
  4. 持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。

3、Spring 事务管理

Spring 把事务处理流程做了一致性的抽象(PlatformTransactionManager接口),具体的事务管理交由各种事务管理器提供实现,类似于JDBC接口规范和各种数据库实现。

4、Spring声明式事务(注解)

①pom依赖

  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>4.3.14.RELEASE</version>
  </dependency>

② 持久层 接口

public interface DeptDao {
     public  Integer add(DeptModel model) throws  Exception;
}
public interface EmpDao {
     public  Integer  add(EmpModel model) throws  Exception;
}
   持久层 实现


@Repository
public class DeptDaoImpl implements DeptDao {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public Integer add(DeptModel model) throws Exception {
        String sql = "insert into tb_department(dept_no,dept_name,dept_loc) values ( ?, ?, ?)";
       int row= jdbcTemplate.update(sql,model.getDeptNo(),model.getDeptName(),model.getDeptLoc());
        return row;
    }
}
​
@Repository
public class EmpDaoImpl implements EmpDao {
    @Autowired
    private JdbcTemplate  jdbcTemplate;
    @Override
    public Integer add(EmpModel model) throws Exception {
        String sql = "insert into tb_employee values( ?,?,?,?,? )";
        int row=   jdbcTemplate.update(sql, model.getEmpNo(),model.getEmpName(),model.getEmpTel(),model.getEmpAddress(),model.getDeptNo());
        return row;
    }
}

③服务层 接口

public interface EmpService {
    //保存 员工 
    public Integer   saveEmp(EmpModel empModel, DeptModel deptModel) throws  Exception;
}

④服务层 实现

@Service("empService")
public class EmpServiceImpl  implements EmpService {
    @Autowired
    private EmpDao  empDao;
    @Autowired
    private DeptDao  deptDao;
  
    @Override
    @Transactional
    public Integer saveEmp(EmpModel empModel, DeptModel deptModel) throws Exception {
        int row1=  deptDao.add(deptModel);
        int row2=  empDao.add(empModel);
        return row1+row2;
    }
}

⑤ 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:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
      <!--包扫描-->
      <context:component-scan base-package="com.xingxue.spring"/>
      <!--注解配置-->
      <context:annotation-config/>
      <!-- 引入外部配置文件(自动注册 PropertyPlaceholderConfigurer Bean) -->
      <context:property-placeholder location="classpath*:db.properties"/>
      <!--配置数据源-->
      <bean  id="dataSource"  class="com.alibaba.druid.pool.DruidDataSource">
               <property name="username" value="${jdbc.user}"/>
               <property name="password" value="${jdbc.password}"/>
               <property name="url" value="${jdbc.url}"/>
               <property name="driverClassName" value="${jdbc.driverClassName}"/>
       </bean>
      <!-- 注册jdbctemplate -->
      <bean id="jdbcTemplate"  class="org.springframework.jdbc.core.JdbcTemplate">
             <property name="dataSource" ref="dataSource"/>
      </bean>
      <!-- 配置事务管理器 -->
      <bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
             <property name="dataSource" ref="dataSource"></property>
      </bean>
     <!--  开启事务注解配置 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

xml依赖配置

    <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjweaver</artifactId>
       <version>1.8.13</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.14.RELEASE</version>
    </dependency>

xml 配置

    <!--Aop 声明式事务配置 -->
    <aop:config>
           <aop:pointcut id="pointcut" expression="execution( *  com.xingxue.spring.service..*.*(..) )"/>
           <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
    </aop:config>
    <!--事务通知-->
    <tx:advice transaction-manager="transactionManager" id="txAdvice">
               <tx:attributes>
                   <tx:method name="*"/>
                   <tx:method name="get*" read-only="true"/>
                   <tx:method name="find*" read-only="true"/>
               </tx:attributes>
    </tx:advice>

八、整合Maven+Spring+Mybaits+Struts2+Log4j

 

猜你喜欢

转载自blog.csdn.net/qq_36120342/article/details/82500503