1、Spring

1.1、简介

  • Spring : 春天 --->给软件行业带来了春天
  • 2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
  • 2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
  • 很难想象Rod Johnson的学历 , 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学
  • Spring理念 : 使现有技术更加实用,本身就是一个大杂烩 , 整合现有的框架技术
  • SSH:Struts2+Spring+Hibernate
  • SSM:SpringMVC+Spring+Mybatis

官网 : http://spring.io/

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

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

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

1.2、优点

  • 1、Spring是一个开源免费的框架 , 容器 !
  • 2、Spring是一个轻量级的框架 , 非侵入式的 !
  • 3、控制反转 IoC , 面向切面编程 Aop
  • 4、对事物的支持 , 对框架整合的支持!

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

1.3、组成

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

图片说明

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

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

1.4、扩展

在Spring的官网中介绍:现代化Java开发,就是基于Spring的开发!

图片说明

  • Spring Boot
    • 一个快速开发的脚手架
    • 基于Spring Boot可以快速开发单个微服务。
    • 约定大于配置!
  • Spring Cloud
    • SpringCloud是基于SpringBoot实现的。

现在大多数公司都是在使用SpringBoot进行快速开发,学习Spring Boot的前提,需要完全掌握Spring及SpringMVC!

Spring弊端:发展太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱!”

2、IOC理论推导

  1. UserDao接口

    public interface UserDao {
        public void getUser();
    }
  2. UserDaoImpl实现类

    public class UserDaoImpl implements UserDao {
    
        @Override
        public void getUser() {
            System.out.println("默认获取用户数据");
        }
    }
    
    public class UserDaoMySQLImpl implements UserDao {
    
        @Override
        public void getUser() {
            System.out.println("MySQL获取用户数据");
        }
    }
  3. UserService业务接口

    public interface UserService {
        public void getUser();
    }
  4. UserServiceImpl业务实现类

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

在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改源代码!如果程序代码量十分庞大,那么修改一次的成本十分昂贵!

图片说明

我们使用一个Set接口实现:

private UserDao userDao;

public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}
  • 之前,程序员主动创建对象,控制权在程序员手上!
  • 使用了set注入后,程序不再具有主动性,而是变成了被动的接收对象!

这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注于业务实现上!这是IOC的原型!

图片说明

IOC本质

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

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

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

3、HelloSpring

3.1、导入jar包

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

3.2、编写代码

  1. 编写一个Hello实体类

    public class Hello {
    
        private String str;
    
        public String getStr() {
            return str;
        }
    
        public void setStr(String str) {
            this.str = str;
        }
    
        @Override
        public String toString() {
            return "Hello{" +
                    "str='" + str + '\'' +
                    '}';
        }
    }
  2. 编写我们的spring文件 , 这里我们命名为applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="hello" class="com.hardy.pojo.Hello">
            <property name="str" value="Spring"/>
        </bean>
    
    </beans>
  3. 测试

    public class MyTest {
    
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            Hello hello = (Hello) applicationContext.getBean("hello");
            System.out.println(hello);
        }
    }

3.3、思考问题?

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

这个过程就叫控制反转 :

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

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

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

要实现不同的操作 , 只需要在xml配置文件中进行修改 , 所谓的IoC,一句话搞定 : 对象由Spring 来创建 , 管理 , 装配!

4、IOC创建对象的方式

  1. 使用无参构造创建对象,默认!【提供无参构造函数】

    <bean id="user" class="com.hardy.pojo.User"/>
  2. 使用有参构造创建对象。

    1. 下标赋值

      <bean id="user" class="com.hardy.pojo.User">
          <constructor-arg index="0" value="hardy"/>
      </bean>
    2. 类型赋值【不建议使用,多个参数相同类型时出错】

      <bean id="user" class="com.hardy.pojo.User">
          <constructor-arg type="java.lang.String" value="tom"/>
      </bean>
    3. 参数名

      <bean id="user" class="com.hardy.pojo.User">
          <!--<constructor-arg index="0" value="hardy"/>-->
          <!--<constructor-arg type="java.lang.String" value="tom"/>-->
          <constructor-arg name="name" value="jack"/>
      </bean>

总结:在配置文件加载的时候,容器中管理的对象就已经被初始化了!

5、Spring配置

5.1、别名

<alias name="user" alias="userNew"/>

5.2、Bean的配置

<bean id="user" class="com.hardy.pojo.User" name="别名1 别名2">
    <property name="name" value="tom"/
</bean>

5.3、import

团队的合作通过import来实现 ,可将多个配置文件导入合并为一个!

假设有多人共同开发项目,分别负责不同的类开发,并注册在不同的配置文件中,可利用import将所有人的配置文件导入applicationContext.xml中。

<import resource="classpath:bean1.xml"/>
<import resource="classpath:bean2.xml"/>

6、依赖注入

6.1、构造器注入

详见 4、IOC创建对象方式

6.2、Set方式注入【重点】

  • 依赖注入:Set注入!
    • 依赖:bean对象的创建依赖于容器!
    • 注入:bean对象中的所有属性,有容器来注入!

【环境搭建】

  1. 复杂类型

    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 + '\'' +
                    '}';
        }
    }
  2. 真实测试对象

    public class Student {
    
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobbys;
        private Map<String,String> cards;
        private Set<String> games;
        private String wife;
        private Properties info;
    }
  3. applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="student" class="com.hardy.pojo.Student">
            <property name="name" value="Hardy"/>
            <property name="address" ref="address"/>
            <!--array-->
            <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="cards">
                <map>
                    <entry key="身份证" value="111111111111"/>
                    <entry key="银行卡" value="222222222222"/>
                </map>
            </property>
            <!--set-->
            <property name="games">
                <set>
                    <value>LOL</value>
                    <value>COC</value>
                    <value>BOB</value>
                </set>
            </property>
            <!--null-->
            <property name="wife">
                <null/>
            </property>
            <!--properties-->
            <property name="info">
                <props>
                    <prop key="学号">17722134</prop>
                    <prop key="性别">男</prop>
                </props>
            </property>
        </bean>
    
        <bean id="address" class="com.hardy.pojo.Address">
            <property name="address" value="上海普陀"/>
        </bean>
    
    
```
  1. 测试类

    public class MyTest {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            Student student = context.getBean("student",Student.class);
            System.out.println(student);
        }
    }

6.3、拓展方式注入

  1. p命名空间注入

    <bean id="user" class="com.hardy.pojo.User" p:name="jj" p:age="18" p:address-ref="address"/>
  2. c命名空间注入

    <bean id="user2" class="com.hardy.pojo.User"
        c:address-ref="address" c:name="ljj" c:age="33"
    />

注意点:p命名和c命名空间不能直接使用,需要导入xml约束

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

6.4、Bean的作用域

图片说明

  1. 单例模式(Spring默认机制)

    <bean id="user" class="com.hardy.pojo.User" p:name="jj" p:age="18" p:address-ref="address" scope="singleton"/>
  2. 原型模式(多例)

    <bean id="user" class="com.hardy.pojo.User" p:name="jj" p:age="18" p:address-ref="address" scope="prototype"/>
  3. 其余的request、session、application等只能在web开发中用到!

7、Bean的自动装配

  • 自动装配时Spring满足bean依赖的一种方式!
  • Spring会在上下文中自动寻找,并自动给bean装配属性!

在Spring中有三种装配的方式

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配bean【重要】

7.1、测试

环境搭建:一个人拥有两个宠物!

7.2、ByName自动装配

<bean id="person" class="com.hardy.pojo.Person" autowire="byName">
    <property name="name" value="tomcat"/>
</bean>

7.3、ByType自动装配

<bean id="person" class="com.hardy.pojo.Person" autowire="byType">
    <property name="name" value="tomcat"/>
</bean>

小结:

  • byname装配的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性对应set方法名称一致!
  • bytype装配的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

7.4、使用注解实现自动装配

jdk1.5开始支持注解,Spring2.5开始支持注解!

The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.

要使用注解须知:

  1. 导入约束:context约束

  2. 配置注解的支持:==context:annotation-config/==

    <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:annotation-config/>
    
    </beans>

@AutoWired:直接作用在属性上,可以不提供set方法!

@Autowired
private Dog dog;

@Autowired
private Cat cat;

如果@AutoWired自动装配的环境比较复杂,自动装配无法通过一个@AutoWired注解完成的时候,我们可以使用@Qualifier(value="xxx")去配合@AutoWired的使用,指定一个唯一的bean对象注入!

@Autowired
@Qualifier("dog")
private Dog dog;

@Qualifier("cat")
@Autowired
private Cat cat;

@Resource注解

@Resource(name = "cat")
private Cat cat;

小结:

@Resource和@Autowired的异同:

  • 都是用来自动装配的,都可以添加在属性字段上
  • @AutoWired 默认按照类型查找,若有相同类型,则按照名称找。
  • @Resource 默认按照名称查找,找不到则按照类型查找。

8、使用注解开发

在Spring4之后,使用注解开发,必须要保证aop的包导入了

图片说明

使用注解需要导入context约束,增加注解的支持!

<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:annotation-config/>

</beans>

8.1、bean

<bean id="user" class="com.hardy.pojo.User" scope="singleton">
    <constructor-arg name="name" value="jack"/>
</bean>

8.2、属性如何注入

@Component
public class User {

    @Value("chengkai")
    public String name;
}

8.3、衍生的注解

  • @Component有几个衍生注解,在Web开发中,会按照mvc三层架构分层!

    • dao 【@Repository】

    • service 【@Service】

    • controller 【@Controller】

      这四个注解功能都是一样的,都代表将某个类注册到IoC容器中!

8.4、自动装配

@Autowired
@Qualifier("dog")
private Dog dog;

@Resource(name = "cat")
private Cat cat;

8.5、作用域

@Scope("singleton")

8.6、小结

xml于注解:

  • xml更加万能,适用于任何场合,维护简单方便!
  • 注解维护相对复杂

xml于注解最佳实践:

  • xml用来管理bean

  • 注解用来完成属性的注入

  • 注意:若要让注解生效,必须开启注解支持!

    <context:component-scan base-package="com.hardy"/>

9、使用Java的方式配置Spring

可以不需要使用xml配置,完全交给Java来做!

JavaConfig时Spring的一个子项目,在Spring4之后,他成为了一个核心功能!

图片说明

实体类

@Component
public class User {

    @Value("ck")
    private String name;

    public String getName() {
        return name;
    }

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

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

配置类

@Configuration
@ComponentScan("com.hardy")
public class AppConfig {

    @Bean
    public User getUser(){
        return new User();
    }
}

测试类

@Test
public void test(){
    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    User user = context.getBean("user", User.class);
    User user2 = context.getBean("getUser", User.class);
    System.out.println(user == user2);
}

这种纯Java的配置方式,在SpringBoot中随处可见!

10、代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层!

代理模式的分类:

  • 静态代理
  • 动态代理

图片说明

10.1、静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,并提供附加操作
  • 客户:访问代理对象的人!

代码步骤:

  1. 接口

    public interface Rent {
    
        public void rent();
    }
  2. 真实角色

    public class Host implements Rent {
        @Override
        public void rent() {
            System.out.println("房东要出租房子!");
        }
    }
  3. 代理角色

    public class Proxy implements Rent {
    
        Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        @Override
        public void rent() {
            seeHouse();
            host.rent();
            deal();
            fee();
        }
    
        public void seeHouse(){
            System.out.println("中介带你看房!");
        }
    
        public void deal(){
            System.out.println("签租赁合同!");
        }
    
        public void fee(){
            System.out.println("收中介费!");
        }
    }
  4. 客户端访问代理角色

    public class Client {
    
        public static void main(String[] args) {
            Proxy proxy = new Proxy(new Host());
            proxy.rent();
        }
    }

代理模式的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务!
  • 公告业务交给代理角色,实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!

缺点:

  • 一个真实角色就会产生一个代理角色,代码量翻倍,开发效率会变低!

10.2、加深理解

聊聊AOP

图片说明

代码:

  • 接口

    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void query();
    }
  • 被代理类

    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 query() {
            System.out.println("查询了一个用户");
        }
    }
  • 代理类

    public class UserServiceProxy implements UserService {
    
        UserService userService;
    
        public UserServiceProxy() {
        }
    
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    
        @Override
        public void add() {
            log("add");
            userService.add();
        }
    
        @Override
        public void delete() {
            log("delete");
            userService.delete();
        }
    
        @Override
        public void update() {
            log("update");
            userService.update();
        }
    
        @Override
        public void query() {
            log("query");
            userService.query();
        }
    
        public void log(String msg){
            System.out.println("使用了"+msg+"方法");
        }
    }

10.3、动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们自己写的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口:JDK动态代理【使用】
    • 基于类:cglib
    • java字节码实现:javassist

需要了解两个类:Proxy,InvocationHandler

动态代理的好处:

  • 可以使真实角色的操作更加纯粹!不用去关注一些公共的业务!
  • 公告业务交给代理角色,实现了业务的分工!
  • 公共业务发生扩展的时候,方便集中管理!
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务!

11、AOP

11.1、什么是AOP

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

图片说明

11.2、AOP在Spring中的作用

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

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....

  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。

  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。

  • 目标(Target):被通知对象。

  • 代理(Proxy):向目标对象应用通知之后创建的对象。

  • 切入点(PointCut):切面通知 执行的 “地点”的定义。

  • 连接点(JointPoint):与切入点匹配的执行点。

图片说明

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

图片说明

即AOP在不改变原有代码的情况下,增加了新的功能!

11.3、使用Spring实现AOP

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

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

方式一:使用Spring的API接口【主要是Spring API接口实现】

  1. 编写业务接口和实现类

    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public int query();
    }
    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 int query() {
            System.out.println("查询了一个用户");
            return 10;
        }
    }
  1. 通过继承Spring的API编写增强类,一个前置增强,一个后置增强

    public class Log implements MethodBeforeAdvice {
    
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了!");
        }
    }
    public class AfterLog implements AfterReturningAdvice {
    
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了!返回结果为:"+returnValue);
        }
    }
  1. 在IoC容器中注册对象 , 并实现aop切入实现 , 注意导入约束

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="userService" class="com.hardy.service.UserServiceImpl"/>
    
        <bean id="log" class="com.hardy.log.Log"/>
    
        <bean id="afterLog" class="com.hardy.log.AfterLog"/>
    
        <!--方式一:使用原生Spring API接口-->
        <aop:config>
            <aop:pointcut id="point" expression="execution(* com.hardy.service.UserServiceImpl.*(..))"/>
            <aop:advisor advice-ref="log" pointcut-ref="point"/>
            <aop:advisor advice-ref="afterLog" pointcut-ref="point"/>
        </aop:config>
    
    
```
  1. 测试

    public class MyTest {
    
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            UserService userService = context.getBean("userService", UserService.class);
            userService.query();
        }
    }

方式二:自定义类实现AOP【主要是切面定义】

  1. 编写自定义切面类

    public class DiyPointCut {
    
        public void before(){
            System.out.println("========方法执行前===before====");
        }
    
        public void after(){
            System.out.println("========方法执行后===finally====");
        }
    
        public void afterReturning(){
            System.out.println("========方法正常执行后=======");
        }
    
        public void afterThrowing(){
            System.out.println("========方法出现异常后=======");
        }
    }
  1. 在Spring中配置切面等

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="userService" class="com.hardy.service.UserServiceImpl"/>
    
        <bean id="diy" class="com.hardy.diy.DiyPointCut"/>
    
        <aop:config>
            <aop:aspect id="diyAspect" ref="diy">
                <aop:pointcut id="point" expression="execution(* com.hardy.service.UserServiceImpl.*(..))"/>
                <aop:before method="before" pointcut-ref="point"/>
                <aop:after method="after" pointcut-ref="point"/>
                <aop:after-returning method="afterReturning" pointcut-ref="point"/>
                <aop:after-throwing method="afterThrowing" pointcut-ref="point"/>
            </aop:aspect>
        </aop:config>
    
    
```
  1. 测试

    public class MyTest {
    
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            UserService userService = context.getBean("userService", UserService.class);
            userService.query();
        }
    }

方式三:使用注解实现

  1. 编写一个注解实现的切面类

    @Aspect
    @Component
    public class AnnotationPointCut {
    
        @Pointcut("execution(* com.hardy.service.UserServiceImpl.*(..))")
        private void point(){}
    
        @Before("point()")
        public void before(){
            System.out.println("====AnnotationPointCut====方法执行前===before====");
        }
    
        @After("point()")
        public void after(){
            System.out.println("====AnnotationPointCut====方法执行后===finally====");
        }
    
        @AfterReturning("point()")
        public void afterReturning(){
            System.out.println("====AnnotationPointCut====方法正常执行后=======");
        }
    
        @AfterThrowing("point()")
        public void afterThrowing(){
            System.out.println("====AnnotationPointCut====方法出现异常后=======");
        }
    
    }
  1. 在Spring中配置切面等 【注意开启aop注解支持】

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="userService" class="com.hardy.service.UserServiceImpl"/>
    
        <aop:aspectj-autoproxy/>
    
        <context:component-scan base-package="com.hardy"/>
    
    
```
  1. 测试

    public class MyTest {
    
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
            UserService userService = context.getBean("userService", UserService.class);
            userService.query();
        }
    }

12、整合Mybatis

步骤:

  1. 导入相关jar包

    • junit
    • mybatis
    • mysql数据库
    • Spring相关的
    • aop织入
    • mybatis-Spring
  2. 编写配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            https://www.springframework.org/schema/aop/spring-aop.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="username" value="root"/>
            <property name="password" value="0208055201314s"/>
        </bean>
    
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
            <property name="dataSource" ref="dataSource"/>
            <property name="configLocation" value="classpath:mybatis-config.xml"/>
           <property name="mapperLocations" value="classpath:com/hardy/mapper/*.xml"/>
        </bean>
    
    
```
  1. 测试

12.1、回忆Mybatis

  1. 编写实体类
  2. 编写核心配置文件
  3. 编写接口
  4. 编写Mapper.xml
  5. 测试

12.2、Mybatis-Spring

  1. 编写数据源配置

  2. sqlSessionFactory

  3. sqlSession获取

    1. sqlSessionTemplate:配置sqlSessionTemplate,并将其注入mapper实现类中,用于操作mapper接口

      <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
          <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
      </bean>
      
      <bean id="userMapper" class="com.hardy.mapper.UserMapperImpl">
          <property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
      </bean>
      public class UserMapperImpl implements UserMapper {
      
          private SqlSessionTemplate sqlSessionTemplate;
      
          public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
              this.sqlSessionTemplate = sqlSessionTemplate;
          }
      
          @Override
          public List<User> selectUser() {
              return sqlSessionTemplate.getMapper(UserMapper.class).selectUser();
          }
      }
    2. sqlSessionDaoSupport:编写mapper实现类,继承sqlSessionDaoSupport,调用父类的getSqlSession()方法获取sqlSession

      <bean id="userMapper2" class="com.hardy.mapper.UserMapperImpl2">
          <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
      </bean>
      public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
          @Override
          public List<User> selectUser() {
              UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
              return mapper.selectUser();
          }
      }
    3. MapperScanner:配置mapperScanner,直接扫描所有mapper接口,生成相应的mapper代理对象

      <bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
          <property name="basePackage" value="com.hardy.mapper"/>
      </bean>
  4. 测试

13、声明式事务

13.1、回顾事务

  • 把一组业务当成整体,要么都成功,要么都失败!
  • 事务在项目开发中十分重要,涉及到数据的一致性问题,不能马虎!
  • 确保完整性和一致性!

事务的ACID原则:

  • 原子性
  • 一致性
  • 隔离性
    • 多个业务可能操作同一各资源,防止数据损坏
  • 持久性
    • 事务一旦提交,无论系统发生什么问题,接管都不会再被影响,被持久化到存储器中!

2、Spring中的事务

  • 声明式事务:AOP

    • 配置transactionManager

      <tx:advice id="txAdvice" transaction-manager="transactionManager">
          <tx:attributes>
              <tx:method name="add*"/>
              <tx:method name="delete"/>
              <tx:method name="update"/>
              <tx:method name="query" read-only="true"/>
              <tx:method name="*"/>
          </tx:attributes>
      </tx:advice>
    • 配置aop:config

      <aop:config>
          <aop:pointcut id="txPointCt" expression="execution(* com.hardy.mapper.*.*(..))"/>
          <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCt"/>
      </aop:config>
  • 编程式事务:需要在代码中,进行事务的管理

思考:

为什么需要事务?

  • 如果不配置事务,可能存在事务提交不一致的情况
  • 如果我们不在Spring中去配置声明式事务,我们就需要在代码中手动配置事务!
  • 事务在项目的开发中十分重要,涉及到数据的一致性和完整性问题,不容马虎!