乐趣区

关于java:万字Spring框架学习总结附核心代码详细注释

前言

大家好,这次爆肝两天给大家总结了一份对于 Spring 框架的知识点,创作不易,点个赞再看吧!

1.Spring 概述

1.1Spring 框架是什么?

Spring 框架是一个凋谢源代码的 J2EE 应用程序框架,由 Rod Johnson 发动,是针对 bean 的生命周期进行治理的轻量级容器(lightweight container)。Spring 解决了开发者在 J2EE 开发中遇到的许多常见的问题,提供了功能强大 IOC、AOP 及 Web MVC 等性能。Spring 能够独自利用于构筑应用程序,也能够和 Struts、Webwork、Tapestry 等泛滥 Web 框架组合应用,并且能够与 Swing 等桌面应用程序 AP 组合。因而,Spring 不仅仅能利用于 J2EE 应用程序之中,也能够利用于桌面应用程序以及小应用程序之中。Spring 框架次要由七局部组成,别离是 Spring Core、Spring AOP、Spring ORM、Spring DAO、Spring Context、Spring Web 和 Spring Web MVC。

1.spring 全家桶: spring,springmvc,spring boot,spring cloud

2.spring: 呈现是在 2002 左右,解决企业开发的难度。加重对我的项目模块之间的治理, 类和类之间的治理,帮 助开发人员创建对象,治理对象之间的关系。spring 核心技术 ioc ,aop。能实现模块之间,类之间的解耦合。

1.2Spring 的长处

1. 轻量

spring 框架应用的 jar 比拟小,都在 1M 一下或者几百 kb。spring 外围性能的所需的 jar 总共在 3M 左右。spring 框架运行时占用的资源少,运行效率高,不依赖别的 jar。

2. 针对接口编程,解耦合

spring 提供了 Ioc 管制反转,由容器治理对象,对象的依赖关系。原来在程序代码中的对象创立形式,现状由容器实现。对象之间的依赖解耦合。

3.AOP 编程的反对

通过 Spring 提供的 AOP 性能,不便进行面向切面的编程,许多不容易用传统 0OP 实现的性能能够通过 AOP 轻松应酬,在 Spring 中,开发人员能够从繁冗的事务管理代码中解脱进去,通过申明式形式灵便地进行事务的治理,进步开发效率和品质。

4. 不便集成各种优良的框架

Spring 不排挤各种优良的开源框架,相同 Spring 能够升高各种框架的应用难度,Spring 提供了对各种优良框架(如 Struts,Hibernate、MyBatis) 等的间接反对。简化框架的应用。Spring 像插线板一样,其余框架是插头,能够容易的组合到一起。须要应用哪个框架,就把这个插头放入插线板。不须要能够轻易的移除。

1.3Spring 的体系结构

2.Ioc 管制反转

​管制反转(Ioc,Inversion of Control), 是一个概念,一种思维。指将传统上由程序代码间接操控的对象调用权交给容器,通过容器来实现对象的拆卸和治理。管制反转就是对对象控制权的转移,从程序代码自身反转到了内部容器。通过容器实现对象的创立,属性赋值,依赖的治理。

loc 的实现:IoC 是一个概念,是一种思维,其实现形式多种多样。以后比拟风行的实现形式是依赖注入。利用宽泛。

依赖: classA 类中含有 classB 的实例,在 classA 中调用 classB 的办法实现性能,即 classA 对 classB 有依赖。

依赖注入: DI(Dependency Injection),程序代码不做定位查问,这些工作由容器自行实现。

依赖注入 DI 是指程序运行过程中,若须要调用另一个对象帮助时,毋庸在代码中创立被调用者,而是依赖于内部容器,由内部容器创立后传递给程序。

Spring 的依赖注入对调用者与被调用者简直没有任何要求,齐全反对对象之间依赖关系的治理。

Spring 框架应用依赖注入(DI) 实现 IoC。

Spring 容器是一个超级大工厂,负责创立、治理所有的 Java 对象,这些 Java 对象被称为 Bean。Spring 容器治理着容器中 Bean 之间的依赖关系,Spring 应用“依赖注入”的形式来治理 Bean 之间的依赖关系。应用 loC 实现对象之间的解耦合。

2.1 开发工具筹备

利用 maven 工具,创立

实现步骤:1. 创立 maven 我的项目
2. 退出 maven 的依赖
        spring 的依赖,版本 5.3.7
        junit 依赖
3. 创立类(接口和它的实现类),和没有应用框架一样,就是一般的类。4. 创立 spring 须要应用的配置文件
    申明类的信息。这些类由 spring 创立和治理
5. 测试 spring 创立的对象。

2.2Sprig 的第一个程序

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

    <!-- 通知 spring 创建对象
    申明 bean,通知 spring 要创立某个类的对象
    id 是对象的自定义名称(惟一值)。spring 通过这个名称找到对象
    class:类的全限定名称(不能是接口,因为 spring 是反射机制)spring 就实现 SomeService someService = new SomeServiceImpl();
    spring 是把创立好的对象放到了 map 中,spring 框架中有一个 map 寄存对象的。springMap.put(id 的值, 对象)
    例如 springMap.put("someService",new someServiceImpl());
    一个 bean 标签只申明一个对象
    -->
    <bean id="someService" class="cqutlc.service.Impl.someServiceImpl"></bean>

    <!--spring 能创立一个非自定义的类 -->
    <bean id="mydate" class="java.util.Date"/>
</beans>
<!--spring 的配置文件
1.beans 是根标签,spring 中把 Java 对象成为 bean
2.spring-beans.xsd 是束缚文件,和 mybatis 指定的相似
-->
package cqutlc;

import cqutlc.service.Impl.someServiceImpl;
import cqutlc.service.someService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test1 {
    @Test
    public void test1(){someService someService=new someServiceImpl();
        someService.doSome();}

    /*spring 默认创建对象的工夫:在创立 spring 的容器时,他会创立配置文件中的所有对象 */
    @Test
    public void test2(){
        // 应用 spring 容器创立的对象
        //1. 指定 spring 配置文件的名称
        String config="beans.xml";
        //2. 创立示意 spring 容器的对象,ApplicationContext
        //ClassPathXmlApplicationContext;示意从类门路中加载 spring 的配置文件
        ApplicationContext ac=new ClassPathXmlApplicationContext(config);
        //3. 从容器中获取某个对象,你要调用对象的办法,//getBean("配置文件中的 bena 的 id 值");
        someService service=(someService)ac.getBean("someService");
        // 应用 spring 创立好的对象
        service.doSome();}
    /* 获取 spring 容器中的 Java 对象的信息 */
    @Test
    public void test3(){
        String config="beans.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext(config);
        // 应用 spring 提供的办法,获取容器中定义的对象的数量
        int num=ac.getBeanDefinitionCount();
        System.out.println(num);
        // 容器中每个定义的对象的名称
        String[] names= ac.getBeanDefinitionNames();
        for (String name : names) {System.out.println(name);
        }
    }
}

2.3 基于 XML 的 DI

在 spring 配置文件中,给 Java 对象的属性赋值。

di: 依赖注入,示意创建对象,给属性赋值。

di 的实现语法:
1. 在 spring 配置文件中,应用标签和属性实现,叫做基于 xml 的 di 实现
2. 应用 spring 中的注解进行属性的赋值,叫做基于注解的 di 实现。

di 的语法分类
1.set 注入(设置注入):spring 调用类的 set 办法,在 set 办法能够实现属性的赋值

2. 结构注入,spring 调用类的有参构造方法,创建对象。在构造方法中实现赋值。

set 注入实例剖析

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

    <!-- 申明 student 对象
    注入:就是赋值的意思
    简略类型:spring 中规定 Java 的根本数据类型和 string 类型都是简略类型。di:给属性赋值
    1.set 注入(设置注入):spring 调用类的 set 办法,你能够在 set 办法中实现属性赋值
        利用 property

    -->
    <bean id="student" class="cqutlc.ba01.Student">
        <property name="name" value="李四"/><!-- 调用 setName...-->
        <property name="age" value="20"/> 认准 set 办法
    </bean>

</beans>

当属性为援用类型时

2. 援用类型的 set 注入:spring 调用 set 办法
-->
<bean id="student" class="cqutlc.ba02.Student">
    <property name="name" value="李四"/><!-- 调用 setName...-->
    <property name="age" value="24"/>
    <property name="school" ref="school"/>
</bean>
<bean id="school" class="cqutlc.ba02.School">
    <property name="name" value="cqut"/>
    <property name="address" value="cq"/>
</bean>

结构注入

得有结构参数

2. 结构注入 spring 调用类的有参数构造方法,在创建对象的同时给属性赋值
结构注入应用
-->
<bean id="student" class="cqutlc.ba03.Student">
    <constructor-arg name="name" value="lc"/>
    <constructor-arg name="age" value="19"/>
    <constructor-arg name="school" ref="myschool"/>
</bean>
<bean id="myschool" class="cqutlc.ba03.School">
    <property name="name" value="cqut"/>
    <property name="address" value="cq"/>
</bean>

援用类型的主动注入

byName 和 byType

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

    <!--
    援用类型的主动注入:spring 框架依据某些规定能够给援用类型赋值。不必你再给援用类型赋值了
    应用的规定罕用的是
    1.byName(按名称注入):Java 类中援用类型的属性名和 spring 容器中(配置文件)<bean> 的 id 名称一样。且数据类型统一,这样的容器中的 bean,spring 可能赋值给援用类型。2.byType(按类型注入):Java 类中援用类型的数据类型和 spring 容器中(配置文件)<bean> 的 class 是同源关系。<bean id=""class="" outowire="byType">
    -->

    <bean id="student" class="cqutlc.ba04.Student" autowire="byName">
        <property name="name" value="李四"/><!-- 调用 setName...-->
        <property name="age" value="24"/>


        <!--<property name="school" ref="school"/>-->
    </bean>
    <bean id="school" class="cqutlc.ba04.School">
        <property name="name" value="cqut"/>
        <property name="address" value="cq"/>
    </bean>

</beans>

多个配置文件的劣势

1. 每个文件的大小比一个文件要小得多。效率高

2. 防止多人竞争带来的抵触

多文件的调配形式:

1. 按功能模块,一个模块一个配置文件。

2. 按类的性能,数据库相干,做事务处理的,做 service 的。

蕴含关系的配置门路

2.4 基于注解的 DI

通过注解实现 Java 对象的创立,属性赋值

应用注解的步骤

  • 退出 maven 的依赖 spring-context,在你退出 spring-context 的同时,间接退出 spring-aop 的依赖。应用注解必须应用 spring-aop 依赖
  • 在类中退出 spring 的注解(多个不同性能的注解)
  • 在 spring 的配置文件中,退出一个组件扫描器的标签,阐明注解在你的我的项目中的地位。

学习的注解有:
1.@Component 2.@Repository 3.@Service 4.@Controller 5.@Value 6.@Autowired 7.@Resource

简略类型

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

    <!-- 申明组件扫描器(component-scan),
    组件就是 Java 对象,所以就是找 Java 对象
    base-package: 指定注解在你的我的项目中的包名
    component-scan 工作形式:spring 会扫描遍历 base-package 指定的包
    把包中和子包中的所有类,找到类中的注解,依照注解的性能创建对象和给属性赋值。-->
  <context:component-scan base-package="cqutlc.ba01"/>


</beans>
package cqutlc.ba01;

import org.springframework.stereotype.Component;
/*
* @Component:创建对象的,等同于 <bean> 的性能
* 属性 value:就是对象的名称,也就是 bean 的 id 值,value 值是惟一的,创立的对象在整个 spring 容器中就一个
* 地位:在类的下面写注解
* */
// 等同于 <bean id="myStudent" class="cqutlc.ba01.Student"/>
//@Component(value = "myStudent")
// 省略 value
//@Component("myStudent")
// 不指定对象名称,由 spring 提供默认名称(首字母小写类名)
@Component
public class Student {
    private String name;
    private Integer age;

    public void setName (String name) {this.name = name;}

    public void setAge (Integer age) {this.age = age;}

    @Override
    public String toString () {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package cqutlc;

import cqutlc.ba01.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test1 {
    @Test
    public void test(){
        String config="applicationContext.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext (config);
        // 从容器中获取对象
        Student student=(Student) ac.getBean ("student");
        System.out.println (student);
    }

}
* spring 中和 @Component 性能统一,创建对象的注解还有:* @Repository(用在长久层上):放在 dao 的实现类下面,* 示意创立 dao 对象,dao 对象是能拜访数据库的。(长久层注解)*
* @Service(用在业务层类的下面):放在 service 的实现类下面,* 创立 service 对象,service 对象是做业务解决的,能够有事物等性能的。*
* @Controller(用在控制器的下面):放在控制器(处理器)类的下面,创立控制器对象的,* 控制器对象能够接管用户提交的参数和显示申请的处理结果。*
* 以上三个注解的应用语法和 @Component 是一样的,都可能创建对象,然而这三个注解还有额定的性能 ---- 给我的项目分层

指定多个包的三种形式

  • 应用屡次组件扫描器标签,指定不同的包
  • 应用分隔符(分号或者逗号)分隔多个包名
  • 指定父包

援用类型

@Autowired:spring 框架提供的注解,实现援用类型的赋值 spring 中通过注解给援用类型赋值,应用的是主动注入,反对 byName 和 byType@Autowired 默认应用 @byType 主动注入

地位:

1. 在属性定义的下面,无需 set 办法,举荐应用。被援用的类必须提前利用 @Component 注解标识。

2. 在 set 办法的下面

属性:required,是一个 boolean 类型的,默认是 true,示意援用类型失败时,程序报错并终止运行。要是 false 则失常运行,赋值为 null, 最好用 true,能够及时发现谬误!

如果要应用 byName 的形式

1. 在属性的下面加上 @Autowired

2. 在属性下面退出 @Qualifier(vlaue=“bean 的 id”):示意应用指定名字的 bean 实现赋值。

@Resource: 来自于 JDK 中的注解,spring 框架提供了对这个注解性能的反对。能够用它给援用类型赋值,应用的也是主动注入原理,反对 byName,byType。默认是 byName

地位:

1. 在属性定义的下面,无需 set 办法,举荐应用

​ 2. 在 set 办法的下面 先应用 byName 主动注入,如果失败了就会再应用 byType

如何只应用 byName?

须要新减少一个属性 name name 的值为 bean 的 id 名称

3.AOP 面向切面编程

3.1 动静代理

​ 动静代理是指:程序在整个运行过程中基本就不存在指标类的代理类,指标对象的代理只是由代理生成工具(不是实在定义的类)在程序运行时由 JVM 依据反射等机制动静生成,代理对象与指标对象的代理关系在程序运行时确定。

实现形式:
jdk 动静代理,应用 jdk 中的 Proxy, Method, Invocai tonHanderl 创立代理对象。jdk 动静代理要求指标类必须实现接口。
cglib 动静代理: 第三方的工具库,创立代理对象,原理是继承。通过继承指标类,创立子类。子类就是代理对象。要求指标类不能是 final 的,办法也不能是 final 的。

动静代理的作用:

  • 在指标类源代码不变的状况下,加强性能
  • 缩小代码的反复
  • 专一业务逻辑代码
  • 解耦合,让你的业务性能和日志,事务非事务性能拆散

3.2AOP 简介

AOP (Aspect Orient Programming),面向切面编程。面向切面编程是从动静角度思考程序运行过程。

AOP 底层,就是采纳动静代理模式实现的。采纳了两种代理: JDK 的动静代理,与 CGLIB 的动静代理。

AOP 为 Aspect Oriented Programming 的缩写,意为: 面向切面编程,可通过运行期动静代理实现程序性能的对立保护的一种技术。AOP 是 Spring 框架中的一个重要内容。利用 AOP 能够对业务逻辑的各个局部进行隔离,从而使得业务逻辑各局部之间的耦合度升高,进步程序的可重用性,同时进步了开发的效率。(动静代理的规范化,把动静代理的实现步骤,形式都定义好了,让开发人员用一种对立的办法,应用动静代理)。
切面:给你的指标类减少的性能,就是切面,什么日志等(切面的特点:个别都是非业务办法,独立应用的。)

面向切面编程,就是将 穿插业务逻辑封装成切面 ,利用 AOP 容器的性能将切面织入到主业务逻辑中。所谓穿插业务逻辑是指, 通用的、与主业务逻辑无关的代码 ,如安全检查、事务、日志、缓存等。
若不应用 AOP,则会呈现代码纠缠,即穿插业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混淆不清。

如何了解面向切面编程?

  • 须要在剖析我的项目性能时,找出切面。
  • 正当的安顿切面的执行工夫(在指标办法前呢,还是后呢)
  • 正当的平安切面执行地位,在哪个类,哪个办法减少加强

3.3AOP 编程术语

1.Aspect:切面,示意加强的性能,就是一堆代码,实现某个性能。(非业务性能,可独立执行。如:日志,统计信息,权限验证等)

2.JoinPoint: 连接点,连贯你的业务办法和切面地位。其实就是某个类中的业务办法。

3.Pointcut:切入点,指多个连接点办法的汇合。

4. 指标对象:给哪个类的办法减少性能,这个类就是指标对象。

5.Advice:告诉,告诉示意切面性能执行的工夫。

一个切面有三个要害的因素:

  • 切面的性能代码,切面干什么
  • 切面的执行地位,应用 Pointcut 示意切面执行地位
  • 切面执行工夫,应用 advice 示意工夫。

3.4AspectJ 对 AOP 的实现

aop 的实现:aop 是一个标准,是一个动静的一个规范化,一个规范。

aop 的技术实现框架:

1.spring:spring 在外部实现了 aop 标准,能做 aop 的工作。

2.aspectJ:一个开源的专门做 aop 的框架。spring 框架中集成了 aspectJ 框架,通过 spring 就能够应用 aspectJ 的性能了。

aspectJ 框架实现有两种形式:1. 应用 xml 的配置文件(配置全局事务)2. 应用注解,个别都用注解

3.5 学习 AspectJ 框架的应用

如何示意切面的执行工夫?
注解示意:1.@Before 2.@AfterReturning 3.@Around 4.@AfterThrowing 5.@After

如何示意切面执行的地位?
应用的是切入点表达式。

表达式原型为:

execution(modifiers-pattern? ret-type-pattern
         declaring-type-pattern?name-pattern(param-pattern)
         throws-pattern?)

解释:

  • modifiers-pattern 拜访权限类型
  • ret-type-pattern 返回值类型
  • declaring-type-pattern 包名类名
  • name-pattern(param-pattern) 办法名(参数类型和参数个数)
  • throws-pattern 抛出异样类型

?示意可选局部

以上表达式共分为四个局部 execution(拜访权限 办法返回值 办法申明(参数)异样类型)

切入点表达式要匹配的对象就是指标办法的办法名。所以,execution 表达式中显著就是办法的签名。留神,表达式中彩色文字示意可省略局部,各局部间用空格离开。在其中能够应用以下符号:

Aspect 的开发环境

应用 aspectJ 框架实现 aop
应用 aop:目标是给曾经存在的一些类和办法,减少额定的性能,前提是不扭转原来的类的代码。框架的应用步骤:1. 新建 maven 我的项目
2. 退出依赖
    spring 依赖 aspectJ 依赖 junit 单元测试
3. 创立指标类:接口和他的实现类
    要做的是给类中的办法去减少性能
4. 创立切面类:一般类
        1. 在类的下面退出 @Aspect
        2. 在类中去定义方法 --- 要执行的性能代码
        3. 在办法的下面退出 aspectJ 中的告诉注解,例如 @Before
          还须要指定切入点表达式 execution()
5. 创立 spring 的配置文件,在文件中申明对象,把对象交给容器对立治理
   申明对象能够应用注解或者 xml 配置文件
   申明指标对象
   申明切面类对象
   申明 aspectJ 框架中的主动代理生成器标签(用来实现代理对象的主动创立性能的)6. 创立测试类,从 spring 容器中获取指标对象(实际上是代理对象)。通过代理执行办法,实现 aop 的性能加强

@Before 实现的一个例子

package cqutlc.ba01;

public interface SomeSevice {void doSome(String name,Integer age);
}
package cqutlc.ba01;
// 指标类
public class SomeSeviceImpl implements SomeSevice {

    @Override
    public void doSome (String name, Integer age) {
        // 给 doSome 办法减少一个性能,在 doSome 办法执行之前,输入办法的执行工夫
        System.out.println ("指标办法执行");
    }
}
package cqutlc.ba01;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Date;

/*
*
@Aspect:aspectJ 框架中的注解,用来示意以后类是切面类
* 地位:类定义的下面
* */
@Aspect
public class MyAspect {
    /*
    * 定义方法:实现切面性能的、* 办法的定义要求:* 1. 公共办法
    * 2. 没有返回值 3. 办法名自定义 4. 办法能够有参数也能够没有参数,有几个参数类型能够应用()
    * */
    /*@Before 前置告诉注解
    * 属性:value,切入点表达式,示意切面的性能执行的地位
    * 特点:在指标办法之前先执行,不会扭转指标办法的执行后果,不会影响指标办法的执行
    * */
    @Before (value = "execution(public void *..SomeSeviceImpl.doSome(..))")
    public void myBefore(){
        // 性能代码
        System.out.println ("工夫:"+new Date ());
    }

}
<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 把对象交给 spring 容器,由容器对立创立和治理对象 -->
    <!-- 申明指标对象 -->
    <bean id="someService" class="cqutlc.ba01.SomeSeviceImpl"/>
    <!-- 申明切面类对象 -->
    <bean id="myAspect" class="cqutlc.ba01.MyAspect"/>
    <!-- 申明主动代理生成器: 应用 aspectJ 框架外部的性能,创立指标对象的代理对象
    创立代理对象是在内存中实现的,批改指标对象的内存中的构造,创立为代理对象
    所以指标对象就是被批改后的代理对象

    aspectj-autoproxy: 会把 spring 容器中的所有的指标对象,一次性都生成代理对象。-->
    <aop:aspectj-autoproxy/>
</beans>
package cqutlc.ba01;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test1 {

    @Test
    public void test1(){
        String config="applicationContext.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext (config);
        SomeSevice proxy=(SomeSevice)ac.getBean ("someService");
        // 通过代理的对象执行办法,实现目标办法执行时,加强了性能。proxy.doSome ("lisi",20);
    }
}

JoinPoint

指定告诉办法中的参数

joinpoint:业务办法,要退出切面性能的业务办法

作用是:能够在告诉办法中获取办法执行时的信息,例如,办法名称,办法的实参。

如果你的切面性能中须要用到办法的信息,就退出 joinpoint

这个 joinpoint 参数的值是由框架赋予,必须是第一个地位的参数。

@Aspect
public class MyAspect {@Before (value = "execution(public void *..SomeSeviceImpl.doSome(..))")
    public void myBefore(JoinPoint jp){
        // 获取办法的残缺定义
        System.out.println("办法的定义:"+jp.getSignature());
        System.out.println("办法的名称:"+jp.getSignature().getName());
        // 获取办法的实参
        Object[] args= jp.getArgs();
        for(Object arg: args){System.out.println("参数 ="+arg);
        }
        // 性能代码
        System.out.println ("工夫:"+new Date ());
    }

}

@AfterReturning

package cqutlc.ba02;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.util.Date;
/*
*
@Aspect:aspectJ 框架中的注解,用来示意以后类是切面类
* 地位:类定义的下面
* */
@Aspect
public class MyAspect {
    /*
    * 后置告诉定义方法:实现切面性能的、* 办法的定义要求:* 1. 公共办法
    * 2. 没有返回值 3. 办法名自定义 4. 办法有参数, 举荐应用 object,参数名自定义
    * */
    /*
    * @AfterReturning
    * 属性:* 1.value: 切入点表达式
    * 2.returning:自定义的变量,用来示意指标办法的返回值,自定义变量名必须和告诉办法的形参名一样
    * 特点:* 1. 在指标办法之后执行的
    * 2. 可能取得指标办法的返回值,能够依据这个返回值做不同的解决性能
    *   Object res = doOther();
    * 3. 能够批改这个返回值。* */
    @AfterReturning(value = "execution(* *..SomeSeviceImpl.doOther(..))",
            returning = "res")
    public void myAfterReturing(Object res){
        //Object res:是指标办法执行后的返回值,依据返回值做你的切面的性能解决
        System.out.println ("后置告诉, 获取的返回值是"+res);
        if (res.equals ("abc")){res="hi";}else
        {}}
}

@Around 盘绕告诉 - 加强办法有 ProceedingJoinPoint 参数

package cqutlc.ba03;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Date;

/*
*
@Aspect:aspectJ 框架中的注解,用来示意以后类是切面类
* 地位:类定义的下面
* */
@Aspect
public class MyAspect {
   /*
   * 盘绕告诉定义方法的格局
   * 1.public
   * 2. 有一个返回值 object
   * 3. 办法名称自定义
   * 4. 办法有参数,固定的 ProceedingJoinPoint
   *
   * */
   /*@Around
   特点:1. 性能最强的告诉
   2. 在指标办法前和后都能够退出性能
   3. 控制目标办法是否被调用履行
   4. 批改原来的指标办法的执行后果,影响最初的调用后果
   盘绕告诉等同于 jdk 动静代理,InvocationHandler 接口
   参数:ProceedingJoinPoint 就等同于 Method
   作用:执行指标办法的执行后果,能够被批改。盘绕告诉:常常做事务,在指标办法之前开启事务,执行指标办法,在指标办法之后提交事务
   * */
   @Around (value = "execution(* *..SomeServiceImpl.doFirst(..))")
   public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
       String name="";
       Object[] args =pjp.getArgs ();
       if (args!=null&&args.length>1){Object arg= args[0];
           name=(String)arg;
       }
       // 在指标办法前或者后加性能
       // 实现盘绕告诉
       Object result=null;
       System.out.println ("盘绕告诉在指标办法之前"+new Date ());
       if ("zhangsan".equals (name)){
           //1. 实现目标办法的调用
           result= pjp.proceed ();//method.invoke,object result=doFirst();
       }

       System.out.println ("盘绕告诉在指标办法之后,提交事务");

       return  result;

   }

}
package cqutlc.ba03;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class test1 {

    @Test
    public void test1(){
        String config="applicationContext.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext (config);
        SomeService proxy=(SomeService)ac.getBean ("someService");
        String str=proxy.doFirst ("lc",19);


    }
}

@Pointcut 定义切入点

当较多的告诉加强办法应用雷同的 execution 切入点表达式时, 编写、保护均较为麻烦。
AspectJ 提供了 @Pointcut 注解,用于定义 execution 切入点表达式。其用法是,将 @Pointcut 注解在一个办法之上,当前所有的 execution 的 value 属性值均可应用该办法名作为切入点。代表的就是 @Pointcut 定义的切入点。这个应用 @Pointcut 注解的办法个别应用 private 的标识办法,即没有理论作用的办法。

属性:value 切入点表达式

地位: 自定义的办法的下面

特点:当应用 @Pointcut 定义在一个办法的下面,此时这个办法的名称就是切入点表达式的别名,其余的告诉中,value 属性就能够应用这个办法名称代替切入点表达式。

@Pointcut(value="execution(* *..SomeServiceImpl.doOther(..))")
private void mypt(){// 无需代码}

有接口也能够应用 cglib 代理

在 xml 中配置 <aop:aspectj-autoproxy proxy-target-class="true"/> 示意通知框架,你要应用 cglib 代理。

4.Spring 集成 MyBatis

把 mybatis 和 spring 框架集成在一起,像一个框架一样应用。

用的技术是:IOC

为什么 ioc 能把 spring 和 mybatis 集成在一起?是因为 ioc 能创建对象,能够把 mybatis 创立的对象交给 spring 对立创立,开发人员从 spring 中获取对象。开发人员不必同时面对两个或多个框架了,就面对一个 spring 就行了。

mybatis 应用步骤: 咱们会应用独立的连接池类替换掉 mybatis 中自带的连接池,把连接池类也交给 spring 创立

spring 须要创立的对象有:

  • 独立的连接池类的对象,应用阿里的 druid 连接池
  • SqlSessionFactory 对象
  • 创立 dao 对象

    spring 和 mybatis 集成
    步骤
    1. 新建 maven 我的项目
    2. 退出依赖  spring 依赖 mybatis 依赖 mysql 驱动 spring 的事务依赖 mybatis 和 spring 集成的依赖(SqlSessionFactory)3. 创立实体类
    4. 创立 dao 接口和 mapper 文件
    5. 创立 mybatis 主配置文件
    6. 创立 service 接口和实现类,属性是 dao
    7. 创立 spring 的配置文件:申明 mybatis 的对象交给 spring 创立
      1. 数据源 dataSource
      2.SqlSessionFactory
      3.Dao 对象
      4. 申明自定义的 service
    8. 创立测试类,获取 service 对象,通过 service 调用 dao 实现数据库的拜访

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

        <!-- 申明数据源 DataSource, 作用是连贯数据库的 -->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">

            <!--set 注入给 DruidDataSource 提供连贯数据库信息 -->
            <property name="url" value="jdbc:mysql://localhost:3306/MySql
            ?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"/><!--setUrl 注入 -->
            <property name="username" value="root"/>
            <property name="password" value="131138"/>
            <property name="maxActive" value="20"/>
    </bean>

    <!-- 申明的是 mybatis 中提供的 SqlSessionFactoryBean 类,这个类外部创立 SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set 注入,把数据库连接池付给了 dataSource-->
        <property name="dataSource" ref="myDataSource"/>
        <!--mybatis 主配置文件的地位
        configLocation 属性是 Resource 类型,读取配置文件
        它的赋值,应用的是 value,指定门路的文件,应用  classpath:示意文件的地位
        -->
        <property name="configLocation" value="classpath:mybatis.xml"/>
    </bean>

    <!-- 创立 dao 对象,应用 SqlSession 的 getMapper(studentDao.class)MapperScannerConfigurer: 在外部调用 getMapper()生产每个 dao 接口的代理对象。-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 指定 sqlSessionFactory 对象的 id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 指定包名,包名是 dao 接口所在的包名
        MapperScannerConfigurer 会扫描这个包中的所有接口,把每个接口都执行一次 getMapper 办法
        失去每个接口的 dao 对象,创立好的 dao 对象放入到 spring 容器中
        -->
        <property name="basePackage" value="cqutlc.dao"/>
    </bean>

    <!-- 申明 service-->
    <bean id="studentService" class="cqutlc.service.Impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao"/>
    </bean>
</beans>

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>
    <!-- 日志 -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!-- 设置别名 -->
    <typeAliases>
            <!--name 所在包的门路 -->
        <package name="cqutlc.domain"/>
    </typeAliases>
    <!--sql mapper 映射文件的地位 -->
    <mappers>
        <!--name 是包名 -->
        <package name="cqutlc.dao"/>

    </mappers>
</configuration>

测试下:

package cqutlc;

import cqutlc.dao.studentDao;
import cqutlc.domain.Student;
import cqutlc.service.Impl.StudentServiceImpl;
import cqutlc.service.StudentService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class test1 {
    @Test
    public void test(){
        String config="applicationContext.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext (config);
        // 获取 spring 容器中 dao 对象
       studentDao studentDao=(studentDao) ac.getBean ("studentDao");
        Student student=new Student (1005,"lc","444@qq.com",20);
        int nums=studentDao.insertStudent (student);
        //spring 和 mybatis 整合在一起应用,事务是主动提交的,无需执行 SqlSession.commit();
        System.out.println (nums);
    }
    @Test
    public void test2(){
        String config="applicationContext.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext (config);
        StudentService studentService=(StudentService) ac.getBean ("studentService");
        Student student=new Student (1006,"jkl","555@qq.com",20);
        int nums=studentService.addStudent (student);
        System.out.println (nums);
    }
    @Test
    public void test3(){
        String config="applicationContext.xml";
        ApplicationContext ac=new ClassPathXmlApplicationContext (config);
        StudentService studentService=(StudentService) ac.getBean ("studentService");
        List<Student> students =studentService.queryStudents ();
        for (Student student : students) {System.out.println (student);
        }
    }

}

5.Spring 事务

5.1spring 的事务管理

事务本来是数据库中的概念,在 Dao 层。然而个别状况下,须要将事务晋升到业务层,即 Service 层。这样做是为了可能应用事务的个性来治理具体的业务。

5.2spring 事务管理 API

事务的超时工夫:示意一个办法的最长执行工夫,如果办法执行时超过工夫,就进行事务回滚。

单位:秒,整数,默认 -1

事务的流传行为

管制业务办法是否有事务,有的话是什么样的事务。

7 个流传行为:示意你的业务办法调用时,事务在办法之间是如何应用的。

PROPAGATION_REQUIRED:指定的办法必须在事务内执行,若以后存在事务,就退出到以后事务中,若以后没有事务,则创立一个新事务。这种流传行为是最常见的抉择,也是 spring 默认的事务流传行为。

PROPAGATION_REQUIRES_NEW:指定的办法反对以后事务,但若以后没有事务,也能够也非事务形式执行。

PROPAGATION_SUPPORTS:总是创立一个新事务,若以后存在事务,就将以后事务挂起,直到新事务执行结束。

总结 spring 事务:

1. 治理事务的是,事务管理和它的实现类

2.spring 的事务是一个对立的模型。

​ 指定要应用的事务管理器实现类,应用 bean

​ 指定哪些类,哪些办法须要退出事务管理性能

​ 指定办法须要的隔离级别和流传行为,超时。

5.3 程序举例环境搭建

模仿一个销售零碎

package cqutlc.service;

import cqutlc.dao.GoodsDao;
import cqutlc.dao.SaleDao;
import cqutlc.domain.Goods;
import cqutlc.domain.Sale;
import cqutlc.excep.NotEnoughException;

public class BuyGoodsServiceImpl implements BuyGoodsService {

    private SaleDao saleDao;
    private GoodsDao goodsDao;

    public void setSaleDao (SaleDao saleDao) {this.saleDao = saleDao;}

    public void setGoodsDao (GoodsDao goodsDao) {this.goodsDao = goodsDao;}

    /**/
    @Override
    public void buy (Integer goodsId, Integer nums) {System.out.println ("buy 办法的开始");
        // 记录销售信息
        Sale sale=new Sale ();
        sale.setGid (goodsId);
        sale.setNums (nums);
        saleDao.insertSale (sale);
        // 更新库存
        Goods goods=goodsDao.selectGoods (goodsId);
        if (goods==null){throw new NullPointerException ("编号是:"+goodsId+"商品不存在");
        }else if(goods.getAmount ()<nums) {
            // 库存有余
            throw new NotEnoughException("编号是:"+goodsId+"库存有余!");
        }
        Goods buyGoods=new Goods ();
        buyGoods.setId (goodsId);
        buyGoods.setAmount (nums);
        goodsDao.updateGoods (buyGoods);
        System.out.println ("buy 办法的完结");

    }
}

5.4 应用 spring 的事务注解治理事务

两种处理事务的办法:

1. 适宜于中小我的项目应用的:注解办法

spring 框架本人用 aop 实现给业务办法减少事务的性能,应用 @Transactional注解减少事务

应用 @Transactional 的步骤

1. 须要申明事务管理器对象

<bean id="xx" class="DataSourceTransactionManager">

2. 开启事务注解驱动,通知 spring 框架,我要应用注解的形式治理事务。

spring 应用 aop 机制,创立 @Transactional 所在的类代理对象,给办法退出事务的性能。

​ spring 给业务办法退出事务:在你的业务办法执行之前,先开启事务,在业务办法执行完结后提交或者回滚事务,应用 aop 的盘绕告诉

3. 在办法上退出 @Transactional

<!-- 应用 spring 的事务处理 -->
<!-- 申明事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <!-- 连贯的数据库,制订数据源 -->
    <property name="dataSource" ref="myDataSource"/>
</bean>
<!--2. 开启事务注解驱动,通知 spring 应用注解治理事务,创立代理对象
transactionManager: 事物管理器对象 id-->
<tx:annotation-driven transaction-manager="transactionManager"/>
/*
* rollbackFor 示意产生指定的异样肯定回滚
* */
@Transactional(
        propagation = Propagation.REQUIRED,
        isolation = Isolation.DEFAULT,
        readOnly = false,
        rollbackFor = {NullPointerException.class,NotEnoughException.class}
)
@Override
.... 省略(同上

5.5 应用 AspectJ 的 AOP 配置管理事务

适宜大型项目,有很多的类,办法,须要大量的配置事务,应用 aspectJ 框架性能,在 spring 配置文件中申明类,办法须要的事务。这种形式业务办法和事务配置齐全拆散。

实现步骤:都是在 xml 配置文件中实现。

1. 要应用的是 aspectJ 框架须要退出对应的依赖。

2. 申明事务管理器对象

<bean id="xx" class="DataSourceTransactionManager">

3. 申明办法须要的事务类型(配置办法的事物属性【隔离级别,流传行为,超时】)

4. 配置 aop,哪些类须要创立代理。

6.Spring 与 Web

web 我的项目中容器对象只须要创立一次,把容器对象放入到全局作用域 ServletContext 中。

怎么实现:

​ 应用监听器,当全局作用域对象被创立时,创立容器存入 ServletContext

​ 监听器作用:

​ 1. 创立容器对象,执行ApplicationContext ac=new ClassPathXmlApplicationContext (config);

​ 2. 把容器对象放入到ServletContext,ServletContext.setAttribute(key,ac)

监听器能够本人创立也能够用框架写好的 ContextLoaderListener

web.xml 文件的配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>RegisterServlet</servlet-name>
        <servlet-class>cqutlc.controller.RegisterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>RegisterServlet</servlet-name>
        <url-pattern>/registerServlet</url-pattern>
    </servlet-mapping>

    <!-- 注册监听器 ContextLoaderListener
    监听器被创建对象后,会读取 /WEB-INF/spring.xml
    能够批改默认的文件地位,应用 context-param 从新指定文件的地位

    配置监听器:目标是创立容器对象,创立了容器对象,就能把 spring.xml 配置文件中的所有对象都创立好
    用户发动申请就能够间接调用对象了。-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

</web-app>

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

        <!-- 申明数据源 DataSource, 作用是连贯数据库的 -->
    <bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">

            <!--set 注入给 DruidDataSource 提供连贯数据库信息 -->
            <property name="url" value="jdbc:mysql://localhost:3306/MySql
            ?useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=GMT"/><!--setUrl 注入 -->
            <property name="username" value="root"/>
            <property name="password" value="131138"/>
            <property name="maxActive" value="20"/>
    </bean>

    <!-- 申明的是 mybatis 中提供的 SqlSessionFactoryBean 类,这个类外部创立 SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--set 注入,把数据库连接池付给了 dataSource-->
        <property name="dataSource" ref="myDataSource"/>
        <!--mybatis 主配置文件的地位
        configLocation 属性是 Resource 类型,读取配置文件
        它的赋值,应用的是 value,指定门路的文件,应用  classpath:示意文件的地位
        -->
        <property name="configLocation" value="classpath:mybatis.xml"/>
    </bean>

    <!-- 创立 dao 对象,应用 SqlSession 的 getMapper(studentDao.class)MapperScannerConfigurer: 在外部调用 getMapper()生产每个 dao 接口的代理对象。-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 指定 sqlSessionFactory 对象的 id-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 指定包名,包名是 dao 接口所在的包名
        MapperScannerConfigurer 会扫描这个包中的所有接口,把每个接口都执行一次 getMapper 办法
        失去每个接口的 dao 对象,创立好的 dao 对象放入到 spring 容器中
        -->
        <property name="basePackage" value="cqutlc.dao"/>
    </bean>

    <!-- 申明 service-->
    <bean id="studentService" class="cqutlc.service.Impl.StudentServiceImpl">
        <property name="studentDao" ref="studentDao"/>
    </bean>
</beans>

RegisterServlet 类

package cqutlc.controller;

import cqutlc.domain.Student;
import cqutlc.service.StudentService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class RegisterServlet extends HttpServlet {protected void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {request.setCharacterEncoding("UTF-8");

        String strId=request.getParameter ("id");
        String strName=request.getParameter ("name");
        String strEmail=request.getParameter ("email");
        String strAge=request.getParameter ("age");

        // 创立 spring 的容器对象
        //String config="spring.xml";
        //ApplicationContext ac=new ClassPathXmlApplicationContext (config);
        /*WebApplicationContext ac=null;
        // 获取 servletContext 中的容器对象,创立好的容器对象,拿来就用
        String key=WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
        Object attr= getServletContext ().getAttribute (key);
        if (attr!=null){ac=(WebApplicationContext)attr;
        }*/
        WebApplicationContext ac=null;
        ServletContext sc=getServletContext ();
        ac=WebApplicationContextUtils.getRequiredWebApplicationContext (sc);

        System.out.println ("容器对象的信息 =="+ac);
        // 获取 service
        StudentService studentService=(StudentService) ac.getBean ("studentService");
        Student student=new Student ();
        student.setId (Integer.parseInt (strId));
        student.setName (strName);
        student.setEmail (strEmail);
        student.setAge (Integer.parseInt (strAge));
        studentService.addStudent (student);
        // 给一个后果页面
        request.getRequestDispatcher ("/result.jsp").forward (request,response);
    }

    protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}}
protected void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}

到这里就完结了,如果有什么疑难,欢送评论,一起学习,一起提高 O(∩_∩)O 下次想看我总结什么呢,能够在评论留言哦

退出移动版