首页 > 技术文章 > Spring复习总结

yangj-Blog 2020-05-29 19:23 原文

 

中文文档

https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/core.html#beans

spring官网

https://spring.io/

spirng开发依赖

 快速入门

                                            https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html




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

  

 

狂神笔记

 

spring的七大组成

 

 

 

1)核心模块

        Spring Core模块是Spring的核心容器,它实现了IOC模式,提供了Spring框架的基础功能。此模块中包含的BeanFactory类是Spring的核心类,负责JavaBean的配置与管理。它采用Factory模式实现了IOC即依赖注入。谈到JavaBean,它是一种 Java 类,它遵从一定的设计模式,使它们易于和其他开发工具和组件一起使用。定义 JavaBean 是一种JAVA 语言写成的可重用组件。要编写JavaBean,类必须是具体类和公共类,并且具有无参数的构造器。

2)Context模块

       Spring Context模块继承BeanFactory(或者说Spring核心)类,并且添加了事件处理、国际化、资源装载、透明装载、以及数据校验等功能。它还提供了框架式的Bean的访问方式和很多企业级的功能,如JNDI访问、支持EJB、远程调用、集成模板框架、Email和定时任务调度等。

3)AOP模块

      Spring集成了所有AOP功能。通过事务管理可以使任意Spring管理的对象AOP化。Spring提供了用标准Java语言编写的AOP框架,它的大部分内容都是基于AOP联盟的API开发的。它使应用程序抛开EJB的复杂性,但拥有传统EJB的关键功能。

4)DAO模块

      DAO是 Data Access Object的缩写,DAO模式思想是将业务逻辑代码与数据库交互代码分离,降低两者耦合。通过DAO模式可以使结构变得更为清晰,代码更为简洁。DAO模块提供了JDBC的抽象层,简化了数据库厂商的异常错误(不再从SQLException继承大批代码),大幅度减少代码的编写,并且提供了对声明式事务和编程式事务的支持。

5)ORM映射模块

      Spring ORM 模块提供了对现有ORM框架的支持,各种流行的ORM框架已经做得非常成熟,并且拥有大规模的市场,Spring没有必要开发新的ORM工具,它对Hibernate提供了完美的整合功能,同时也支持其他ORM工具。注意这里Spring是提供各类的接口(support),目前比较流行的下层数据库封闭映射框架,如 ibatis, Hibernate等。 

6)Web模块

        此模块建立在Spring Context 基础之上,它提供了Servlet监听器的Context 和 Web应用的上下文。对现有的Web框架,如JSF、Tapestry、Structs等,提供了集成。Structs是建立在MVC 这种公认的好的模式上的,Struts在M、V和C上都有涉及,但它主要是提供一个好的控制器和一套定制的标签库上,也就是说它的着力点在C和V上,因此,它天生就有MVC所带来的一系列优点,如:结构层次分明,高可重用性,增加了程序的健壮性和可伸缩性,便于开发与设计分工,提供集中统一的权限控制、校验、国际化、日志等等。

7)MVC模块

        Spring WebMVC模块建立在Spring核心功能之上,这使它能拥有Spring框架的所有特性,能够适应多种多视图、模板技术、国际化和验证服务,实现控制逻辑和业务逻辑的清晰分离。说说MVC在JSP的作用,如图所示。

 

一、Bean是啥

1、Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化);

 

2、凡是有方法或属性的类都需要实例化,这样才能具象化去使用这些方法和属性;

 

3、规律:凡是子类及带有方法或属性的类都要加上注册Bean到Spring IoC的注解

 

4、把Bean理解为类的代理或代言人(实际上确实是通过反射、代理来实现的),这样它就能代表类拥有该拥有的东西了

 

5、我们都在微博上@过某某,对方会优先看到这条信息,并给你反馈,那么在Spring中,你标识一个@符号,那么Spring就会来看看,并且从这里拿到一个Bean或者给出一个Bean

IOC

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

让我们以一个普通的例子为例

com.yang.dao包下

1、先写一个UserDao接口

public interface UserDao {
   public void getUser();
}

2、再去写Dao的实现类

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

com.yang.service包下

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();
  }
}
Test包下

5、测试一下

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



在这个过程中我们都是用户实际调用的是业务层(service包)根本用户不会接触到Dao层(dao包),
而我们的service业务层也只做了一件事,那就是去调Dao层
这就是原来的方式,其实已经很方便了,用户已经屏蔽了一层,通过private定义类,成属性,然后调用类的方法。
但是我们现在增加一个需求,
如Dao包下新写一个实现类实现UserDao接口或者其他实现UserDao接口类
package caom.yang.dao;

public class UserDaoMysqllmpl implements UserDao{
public void getUser() {
System.out.println("mysql");
}
}

 

 

 

那用的话还的改业务层的包下的实现类如下
public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoMysqllmpl();
   @Override
   public void getUser() {
       userDao.getUser();
  }
}

这样更改源代码过多就引出了IOC的思想出来
看一下我们的业务层如何改动一下(set)
public class UserServiceImpl implements UserService{
private UserDao userDao;
//利用set进行动态的注入
public void setUserDao(UserDao userDao)
{
this.userDao=userDao;
}

// private UserDao userDao = new UserDaoImpl(); 对比
public void getUser() {
userDao.getUser();
}
}
现在我们的业务层就不需要变动,而是由用户自己选择变动即可,

选择UserDaoImpl
     UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDao(new UserDaoImpl());
userService.getUser();
选择UserDaoMysqlImpl
    UserService userService = new UserServiceImpl();
((UserServiceImpl) userService).setUserDao(newUserDaoMysqlImpl());
        userService.getUser();
这个过程中以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 .
程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .这就是IOC的原型
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。
在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
理解了IOC自己开始我们的spring,项目里面升入理解
-----------------------------------------------
入门参照官方文档
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html
-------------------------------------------------
那么在resources下建立一个beans.xml,并在官方文档找到复制配置(文档里相关的翻译成中文叫配置数据元),像Mybatis一样的核心配置
   <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="..." class="...">   <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>

然后就是按照官网步骤实例化容器


ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

拿到了容器我们只需要获取bean就行了即理解为从容器中拿豆子

就以上面的代码优化为例子

先放入容器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="mysqlImpl" class="caom.yang.dao.UserDaoMysqllmpl"/>
    <bean id="oracleImpl" class="caom.yang.dao.UserDaoOraclelmpl"/>
    </bean>
</beans>

<bean>他会干吗,他会读取这个全限定类名反射创建一个对象,并且存入spring 的核心容器中,我们就可通过id来把这个对象取出来

IDEA这里一定点,就是帮你放进容器

 

 

        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        UserServiceImpl userServiceImpl = (UserServiceImpl)context.getBean("mysqlImpl");
        userServiceImpl.getUser();

当然也可以不用强转,这样写也可以

UserServiceImpl userServiceImpl = context.getBean("mysqlImpl",UserServiceImpl.class);

就简单实现了上面一样的功能,

看到这里的实例化容器,需要我们探究一下到底是什么,关系是怎样的

利用IDEA查看它们的关系如下

 

 

 

 

 

 

 

 

 

了解了容器之后再看看注入容器里面的bean

package com.yang.pojo;

public class User {
    private  String  name;
//  默认的  使用无惨对象创建对象
//    public  User(){
//        System.out.println("调用构造");
//    }
//那如果要用有参数的构造函数呢这样解决看beans.xml
    public  User(String name ){
        this.name=name;
    }
    public String getName() {
        return name;
    }

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

bean默认是调用无参构造的,想调用有参构造,如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    默认的调用无惨构造函数的ioc-->
<!--<bean class="com.yang.pojo.User" id="user">-->
<!--</bean>-->
<!-- 调用有参数构造函数的第一种方法-->
<!--    <bean id="user" class="com.yang.pojo.User">-->
<!--        <constructor-arg index="0" value="阳"/>-->
<!--    </bean>-->

    <!--    调用有参数构造函数的第2种方法,但是不建议使用,通过类型创建,容易出错-->
<!--    <bean id="user" class="com.yang.pojo.User">-->
<!--        <constructor-arg type="java.lang.String" value="nihao"/>-->
<!--    </bean>-->

    <!--    调用有参数构造函数的第3种方法,最能接受也最强的,直接通过参数名字设置,ioc构造的最好方式 私认为-->
        <bean id="user" class="com.yang.pojo.User">
            <constructor-arg name="name" value="nihao"/>
        </bean>

<bean id="userTwo" class="com.yang.pojo.UserT"></bean> <alias name="user" alias="userNew"/> //Bean的别名 </beans>

在这里不仅可以用 constructor-arg还能使用 property 属性,不但可以将 String、int 等字面值注入到 Bean 中,还可以将集合、Map 等类型注入到 Bean 中,此外还可以注入其他的 Bean。

spring配置中property作为bean的属性。也就是指一个类中的成员。同时这个成员必须有get和set方法。

看一个有无property对比.没有property

 

 

 有property

 

 

 Import

 

 

 

对于这里bean的一系列操作,文档里都有.当然还有bean的三种创建方式详情见官方文档,平常用的不多就不列举

============================================================================

官方文档1.4.1里面

DI依赖注入

1 构造器注入:也就是前面我们很多实例都是构造器注入
2 set注入(推荐)https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-setter-injection
看一个例子深入理解SET注入
pojo-student
package com.yang.pojo;

import java.util.*;

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 Properties info;
    private String wife;
    set/get/constru
}
里面的Address类
package com.yang.pojo;

public class Address {
    private String  address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}

可以看到这个pojo类包含了各种类型的属性

结果如下

 

 

 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
  https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="com.yang.pojo.Address" id="address">
        <property name="address" value="成都"></property>
    </bean>

    <bean class="com.yang.pojo.Student" id="student">
<!--        第一种,普通值注入-->
        <property name="name" value="yang"/>
<!--        第二种,Bean注入,ref-->
        <property name="address" ref="address"/>
<!--        第三种,数组注入-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>水浒</value>
                <value>三国演义</value>
            </array>
        </property>
<!--        List注入-->
        <property name="hobbys">
            <list>
                <value>听歌</value>
                <value>打篮球</value>
                <value>看电影</value>
            </list>
        </property>
<!--        Map-->
        <property name="card">
            <map>
                <entry key="身份证" value="7546563453"/>
                <entry key="银行卡" value="123456789"/>
            </map>
        </property>
<!--        Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>COC</value>
            </set>
        </property>
<!--        NULL-->
        <property name="wife">
            <null></null>
        </property>
<!--        properties-->
        <property name="info">
            <props>
                <prop key="学号">2017110146</prop>
                <prop key="性别">男</prop>
            </props>
        </property>

    </bean>
</beans>

3 扩展,p命名和c命名注入


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


 导入约束 : xmlns:p="http://www.springframework.org/schema/p"
 
 <!--P(属性: properties)命名空间 , 属性依然要设置set方法-->
 <bean id="user" class="com.yang.pojo.User" p:name="yang" p:age="18"/>

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


 导入约束 : xmlns:c="http://www.springframework.org/schema/c"
 <!--C(构造: Constructor)命名空间 , 属性依然要设置set方法-->
 <bean id="user" class="com.yang.pojo.User" c:name="yang" c:age="18"/>

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


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

---------------------------------------
自动装配 autowire
XML  autowire byName (按名称自动装配)
   autowire byType (按类型自动装配)
public class Dog {
    public void  shot(){
        System.out.println("wang");
    }
}

public class Cat {
    public void  shot(){
        System.out.println("miao");
    }
}
 
public class People {
    private Cat cat;
    private Dog dog;
    private String name;
  set/get/toString

Peole类里面有Dog和Cat类

没有自动注入的xml如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.yang.pojo.Cat"/>
<bean id="dog" class="com.yang.pojo.Dog"/>
    <bean id="people" class="com.yang.pojo.People" >
        <property name="name" value="Yang"/>
        <property name="dog" ref="dog"/>
        <property name="cat" ref="cat"/>
    </bean>
</beans>

再看看有自动注入的

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.yang.pojo.Cat"/>
<bean id="dog" class="com.yang.pojo.Dog"/>
<!--    byName在上下文自动查找和自己set方法后面的值如setDog找dog对应的bean id,同理的byType-->
    <bean id="people" class="com.yang.pojo.People" autowire="byName">
        <property name="name" value="Yang"/>
<!--        <property name="dog" ref="dog"/>-->
<!--        <property name="cat" ref="cat"/>-->
    </bean>
</beans>

注解实现自动装配

  自动装配即自动导入对象到类中,被注入进的类同样要被 Spring 容器管理

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

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

完整如下
<?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
  https://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  https://www.springframework.org/schema/context/spring-context.xsd">
    <bean id="cat" class="com.yang.pojo.Cat"/>
    <bean id="dogNew" class="com.yang.pojo.Dog"/>
    <bean id="people" class="com.yang.pojo.People"/>
    <context:annotation-config/>
</beans>
public class People {
//    有了这个Autowired就可以自动放入容器中,并且Set方法也可以不用了 false说明可以为null
//    等同于Resource(name="")注解,不过是java的 。@Autowired是spring的
//    @Autowired(required = false)
  @Autowired
private Cat cat;
@Autowired
// 指定装配的值,怕就是一群同类型的装配s所以他也是配合Autowired才使用,还可以赋予value根据value对应 @Qualifier(value = "dogNew") private Dog dog; private String name;
 

-------------------------------------------使用注解开发-*(重点)------------------------------------------

 

学习了上面后发现xml中注册Bean是不是很麻烦,那么下面开始注解开发

在spring4之后,想要使用注解形式,必须得要引入aop的包导入spring-webmvc的依赖就行

application.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
  https://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  https://www.springframework.org/schema/context/spring-context.xsd">
<!--    指定要扫描的包-->
    <context:component-scan base-package="com.yang"/>
<!--    注解支持包括对java的-->
    <context:annotation-config/>
</beans>

 

上面讲了我们一般使用 @Autowired 注解让 Spring 容器帮我们自动装配 bean。要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,可以采用以下注解实现:

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注。
  • @Component三个衍生注解

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

  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。                                                                   dao层
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。                                                         service层
  • @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。    web层

 

 

 

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

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

@Configuration

一般用来声明配置类,可以使用 @Component注解替代,不过使用Configuration注解声明配置类更加语义化。

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }

}

 

 

属性注入

使用注解注入属性

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;
  }
}

 

@scope

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收

@Controller("user")
@Scope("prototype")
public class User {
   @Value("秦疆")
   public String name;
}

 


 =============================================AOP================================

使用AOP织入,需要导入一个依赖包!

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.5</version>
    </dependency>

导入之后可以看到常用方法

 

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

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 {

    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
public class AfterLog implements AfterReturningAdvice {

    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"的方法,返回结果为"+returnValue);
    }
}

同样AOP也要xml加配置

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

       http://www.springframework.org/schema/aop/spring-aop.xsd
第一种方式 通过 Spring API 实现
<?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.yang.service.UserServiceImpl"/>
   <bean id="log" class="com.yang.log.Log"/>
   <bean id="afterLog" class="com.yang.log.AfterLog"/>

   <!--aop的配置-->
   <aop:config>
       <!--切入点 expression:表达式匹配要执行的方法-->
       <aop:pointcut id="pointcut" expression="execution(* com.yang.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 = new ClassPathXmlApplicationContext("beans.xml");
       UserService userService = (UserService) context.getBean("userService");
       userService.search();
  }
}

就会在方法前后运行我们写的log和afterLog

 

 

第二种方式

自定义类来实现Aop

目标业务类不变依旧是userServiceImpl

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

public class DiyPointcut {

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

去spring中配置

<!--第二种方式自定义实现-->
<!--注册bean-->
<bean id="diy" class="com.yang.config.DiyPointcut"/>

<!--aop的配置-->
<aop:config>
   <!--第二种方式:使用AOP的标签实现-->
   <aop:aspect ref="diy">
       <aop:pointcut id="diyPonitcut" expression="execution(* com.yang.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();
  }
}

第三种方式

使用注解实现(推荐)

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

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);
  }
}
@Aspect  //标注这是一个切面
Before After之前之后,Around是(先进先出)

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

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

 

===============================Mybatis-spring=========================

官方网站http://mybatis.org/spring/zh/

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>
spring要操作数据库的话必须要这个
<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>

好了整合依赖完了,让我们回想一下Mybatis需要配置数据元,还有SqlSession那一套

   String resource = "mybatis-config.xml";
   InputStream inputStream = Resources.getResourceAsStream(resource);
   SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
   SqlSession sqlSession = sqlSessionFactory.openSession();

<?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.yang.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.yang.dao"/>
   </mappers>
</configuration>

而Mybatis这些都可以被spring替代所以我们导入依赖需要spring-jdbc需要用spring操作数据库,而spring怎样操作替代mybatis的复杂操作,就出现Mybatis-spring

快速上手

要和 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>

按照管网的指示,先创建spring的xml然后加入上面这段代码

Mybatis-Spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  https://www.springframework.org/schema/context/spring-context.xsd">

    <!--    交给spring管理数据源.一定要对比到MyBatis-config来一起看。看看spring如何整合的-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis1?serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
<!--  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/yang/mapper/UserMapper.xml"/>
    </bean>

运用已经帮你写好的SqlSessionTemplate <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!-- 报错是因为没有注入参数,然后查看源码发现没有set方法,只有通过构造函数注入--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean>
    <context:annotation-config/>
</beans>

<context:annotation-config> 是用于激活那些已经在spring容器里注册过的bean(无论是通过xml的方式还是通过package sanning的方式)上面的注解。

<context:component-scan>除了具有<context:annotation-config>的功能之外,<context:component-scan>还可以在指定的package下扫描以及注册javabean 。

对比一下mybatis配置文件前后关系

MyBatis-config.xml

<?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.yang.pojo"/>
    </typeAliases>
<!--    交给spring管理数据源-->
<!--    <environments default="mysql">-->
<!--        <environment id="mysql">-->
<!--            <transactionManager type="JDBC"></transactionManager>-->
<!--            <dataSource type="POOLED">-->
<!--                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!--                <property name="url" value="jdbc:mysql://localhost:3306/mybatis1?serverTimezone=UTC"/>-->
<!--                <property name="username" value="root"/>-->
<!--                <property name="password" value="root"/>-->
<!--            </dataSource>-->
<!--        </environment>-->
<!--    </environments>-->

<!--    <mappers>-->
<!--        <mapper resource="com/yang/mapper/UserMapper.xml"></mapper>-->
<!--    </mappers>-->


</configuration>

发现MyBatis-config.xml全部都不需要了,甚至别名那个spring也可以,完全可以取代。

数据源被替代了,而Sqlsession也被SqlSessionTemplate替代了变成了面向对象


package com.yang.mapper;

public
interface UserMapper { public List<User> selectUser(); }
package com.yang.mapper;

import com.yang.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl implements UserMapper{

    //原来所有操作都使用sqlsessions执行,现在sqlsessionsTemplate
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

然后我们写了这个实现类注入到Spring中去,并且这个类有一个属性参数是sqlsessiontemplate类型

完整的xml如下

Mybatis-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  https://www.springframework.org/schema/context/spring-context.xsd">

    <!--    交给spring管理数据源.一定要对比到MyBatis-config来一起看。看看spring如何整合的-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis1?serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
=================================================================================== <!-- 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/yang/mapper/UserMapper.xml"/> </bean> <!-- 从这个名字都可看出SqlSessionTemplate就是sqlSession换了个名字而已--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!-- 报错是因为没有注入参数,然后查看源码发现没有set方法,只有通过构造函数注入--> <constructor-arg index="0" ref="sqlSessionFactory"/> </bean> ==================================================================== <bean id="userMapper" class="com.yang.mapper.UserMapperImpl"> <!-- 看函数即可知需要参数为SqlSessionTemplate类型,并且上面的bean配置了这个,所以只需要引用id即可--> <property name="sqlSession" ref="sqlSession"/> </bean> <context:annotation-config/> </beans>

所以等号里的代码基本可以说固定代码,类似于配置

测试就变得极其简单

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

对比之前没整合的

    @Test
public void test()throws IOException {
String resources = "MyBatis-config.xml"; //上面有
InputStream in = Resources.getResourceAsStream(resources);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sqlSessionFactory.openSession(true);

UserMapper mapper = sqlSession.getMapper(userMapper.class);
      List<User> userList = mapper.selectUser();

如果你觉得通过SqlSessinTemplate获得sqlsession太麻烦因为他们还是有一个注入的过程

    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

那么下面你也许可以看一看

方式二

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

看官网:

SqlSessionDaoSupport

SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。调用 getSqlSession() 方法你会得到一个 SqlSessionTemplate

即继承这个support即可用

如:没有注入

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
//    SqlSessionDaoSupport 是一个抽象的支持类,用来为你提供 SqlSession。
//    调用 getSqlSession() 方法你会得到一个 SqlSession
    public List<User> selectUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

直接配置到spring中即可

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


    <import resource="<Mybatis-spring.xml"/>
<bean id="userMapper2" class="com.yang.mapper.UserMapperImpl2">
  //这个类没有属性,但是他的父类Support需要一个Factory
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

</beans>
这个类没有属性,但是他的父类SqlsessionSupport需要一个Factory属性

 ======================================事务(同生共死SQL数据)=========================================

事务四个属性ACID

  1. 原子性(atomicity)

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

  2. 一致性(consistency)

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

  3. 隔离性(isolation)

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

  4. 持久性(durability)

     

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

一个使用 MyBatis-Spring 的其中一个主要原因是它允许 MyBatis 参与到 Spring 的事务管理中。而不是给 MyBatis 创建一个新的专用事务管理器,MyBatis-Spring 借助了 Spring 中的 DataSourceTransactionManager 来实现事务管理。

一旦配置好了 Spring 的事务管理器,你就可以在 Spring 中按你平时的方式来配置事务。并且支持 @Transactional 注解和 AOP 风格的配置。在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。

事务配置好了以后,MyBatis-Spring 将会透明地管理事务。这样在你的 DAO 类中就不需要额外的代码了。

编程式事务管理

  • 将事务管理代码嵌到业务方法中来控制事务的提交和回滚

  • 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码

声明式事务管理

  • 一般情况下比编程式事务好用。

  • 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。

  • 将事务管理作为横切关注点,通过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>

下面来看一个实例

Mybatis-spring.xml(前面的复制过来整改)

mapper包结构如下

 

 

<?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:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  https://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/tx
  https://www.springframework.org/schema/tx/spring-tx.xsd
  http://www.springframework.org/schema/context
  https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">


    <!--    交给spring管理数据源.一定要对比到MyBatis-config来一起看。看看spring如何整合的-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis1?serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>

<!--  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/yang/mapper/*.xml"/>
    </bean>

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        报错是因为没有注入参数,然后查看源码发现没有set方法,只有通过构造函数注入-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>





<!--配置声明式事务.官方文档的-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <constructor-arg ref="datasource" />
    </bean>

<!--    配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        给那些方法配置事务  传播-->
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.yang.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>

    <context:annotation-config/>
</beans>

而这里面的propagation参数如下

 

推荐阅读