狂神Spring教学笔记+源码

1、Spring

所有代码已上传gitee

https://gitee.com/deza-to/learn-spring

1.1、简介

  • Spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架。

  • SSH : Struct2+Spring+Hibernate

  • SSM : SpringMVC+Spring+Mybatis

官网:https://spring.io/projects/spring-framework

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

<!-- 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-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.0.RELEASE</version>
</dependency>

1.2、优点

  • Spring是一个开源的免费的框架(容器)
  • Spring是一个轻量级的,非入侵式的框架
  • 控制反转(IOC),面向切面编程(AOP)
  • 支持事务处理,对框架整合的支持
总结一句话:Spring就是一个轻量级的控制反转和面向切面编程的框架

1.3、组成

1.4、拓展

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

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

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

2、IOC理论推导

  1. UserDao接口
  2. UserDaoImpl实现类
  3. UserService业务接口
  4. UserServiceImpl业务实现
  • 创建Maven项目

    <groupId>com.chen</groupId>
    <artifactId>spring-study</artifactId>
    <version>1.0-SNAPSHOT</version>
    
  • 导入依赖

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

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

我们使用一个Set接口实现

private UserDao userDao;

//利用set进行动态实现值得注入
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、Hello Spring

在resources目录下创建一个xml文件来配置Bean,文件名可以任意,默认是ApplicationContext.xml

文件内容的模板(xml文件头),可以从Spring的官网获取:

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

<?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">
    <!--使用Spring来创建对象,在Spring这些都称为Bean。class不需要带.java-->
    <bean id="hello" class="com.chen.pojo.Hello">
        <property name="name" value="Spring"/>
        <!-- collaborators and configuration for this bean go here -->
    </bean>
</beans>

id:要创建的对象名

class:类型

property:注入属性

测试类获取Spring容器中的对象,并调用其方法:

import com.chen.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    public static void main(String[] args) {
        //获取Spring的上下文对象
        ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //我们的对象现在都在Spring中管理了,我们要使用,直接去里面取来就可以
        Hello hello = (Hello) context.getBean("hello");
        hello.show();
    }
}

思考问题

  • Hello对象是谁创建的?

    Spring创建的

  • Hello对象的属性是怎么设置的

    是由Spring容器设置的

这个过程就叫控制反转

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring之后,对象是由Spring来创建的。

反转:程序本身不创建对象,而变成被动的接收对象。

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

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

可以通过new ClassPathXmlApplicationContext去浏览一下底层源码

OK,到了现在,我们彻底不用再去程序中改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC,一句话搞定:对象由Spring来创建,管理,装配。

4、IOC创建对象的方式

  1. 使用无参构造函数 创建对象,默认。

  2. 假设我们要使用有参构造创建对象。

    1. 下标赋值

      <!--第一种方式,下标赋值-->
      <bean id="user" class="com.chen.pojo.User">
          <constructor-arg index="0" value="peng"/>
      </bean>
      
    2. 类型

      <!--第二种方式,通过类型创建,不建议使用-->
      <bean id="user" class="com.chen.pojo.User">
          <constructor-arg type="java.lang.String" value="旭宝"/>
      </bean>
      
    3. 参数名

      <!--第三种方式,参数名,推荐使用-->
      <bean id="user" class="com.chen.pojo.User">
          <constructor-arg name="name" value="Spring"/>
      </bean>
      

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

5、Spring配置

5.1、别名

<!--别名,如果添加了别名,我们也可以使用别名获取到这个对象-->
<alias name="user" alias="newUser"/>

5.2、Bean的配置

<!--
    id:bean的唯一标识符,也就是相当于对象名
    class:bean对象所对应的全限定名:包名+类名
    name:也是别名,而且name可以同时取多个别名
-->
<bean id="user" class="com.chen.pojo.User" name="user1,user2,user3">
    <constructor-arg name="name" value="Spring"/>
</bean>

5.3、import

一般用于团队开发使用,也可以将多个配置文件导入合并为一个

假设,现在项目中有多个人开发,这三个人负责不同的模块,import将每个人各自编写的配置Bean的xml文件整合在一起。

<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>

6、依赖注入【DI】

6.1、构造器注入

参考前文

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

    public class Student {
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobbies;
        private Map<String,String> card;
        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="address" class="com.chen.pojo.Address"/>
    
        <bean id="student" class="com.chen.pojo.Student">
            <!--第一种,普通值注入,value-->
            <property name="name" value="chen"/>
    
            <!--第二种,Bean注入,ref-->
            <property name="address" ref="address"/>
    
            <!--数组注入,ref-->
            <property name="books">
                <array>
                    <value>三体</value>
                    <value>球形闪电</value>
                    <value>莎士比亚全集</value>
                </array>
            </property>
    
            <!--List-->
            <property name="hobbies">
                <list>
                    <value>吃饭</value>
                    <value>睡觉</value>
                    <value>打豆豆</value>
                </list>
            </property>
    
            <!--Map-->
            <property name="card">
                <map>
                    <entry key="银行卡" value="123456123456"/>
                    <entry key="身份证" value="1111111111122223333"/>
                </map>
            </property>
    
            <!--Set-->
            <property name="games">
                <set>
                    <value>王者荣耀</value>
                    <value>和平精英</value>
                </set>
            </property>
    
            <!--null-->
            <property name="wife">
                <null/>
            </property>
    
            <!--properties-->
            <property name="info">
                <props>
                    <prop key="学号">99021154</prop>
                    <prop key="性别">男</prop>
                    <prop key="username">root</prop>
                    <prop key="password">123456</prop>
                </props>
            </property>
    
        </bean>
    
    </beans>
    
  4. 测试类

    import com.chen.pojo.Student;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            Student student = (Student) context.getBean("student");
            System.out.println(student.getName());
        }
    }
    

6.3、扩展方式注入

可以使用p命名空间和c命名空间进行注入

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

    <!--p命名空间注入,可以直接注入属性的值:property-->
    <bean id="user" class="com.chen.pojo.User" p:name="chen" p:age="18"/>

    <!--c命名空间注入,通过构造器注入:constructor-args-->
    <bean id="user2" class="com.chen.pojo.User" c:age="16" c:name="奥特曼"/>
</beans>

测试

@Test
public void test2(){
    ApplicationContext context = new ClassPathXmlApplicationContext("user.xml");
    User user = context.getBean("user2",User.class);
    System.out.println( user);
}

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

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

6.4、bean的作用域

image-20210622211627117

  1. 单例模式(Spring默认)

    <bean id="user" class="com.chen.pojo.User" p:name="chen" p:age="18" scope="singleton"/>
    
  2. 原型模式:每次从容器中get一个新对象

    <bean id="user2" class="com.chen.pojo.User" c:age="16" c:name="奥特曼" scope="prototype"/>
    
  3. 其余的request、session、application只能在web开发中使用到。

7、Bean的自动装配

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

在Spring中有三种装配方式

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

7.1、ByName自动装配

<bean id="cat" class="com.chen.pojo.Cat"/>
<bean id="dog" class="com.chen.pojo.Dog"/>

<!--byName:会在容器上下文中查找,和自己对象set方法后面的值对应的beanid-->
<bean id="people" class="com.chen.pojo.People" autowire="byName">
    <property name="name" value="旭旭"/>
</bean>

7.2、ByType自动装配

<bean class="com.chen.pojo.Cat"/>
<bean class="com.chen.pojo.Dog"/>

<!--byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean-->
<bean id="people" class="com.chen.pojo.People" autowire="byType">
    <property name="name" value="鹏鹏"/>
</bean>

小结:

  • byName的时候,需要保证所有bean的id唯一,并且这个bean的id需要和自动注入的属性的set方法的值一致。
  • byType的时候,需要保证所有bean的class唯一,并且这个bean的class需要和自动注入的属性的类型一致。

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

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

在实际工作中使用注解的情况更多。

要使用注解须知:

  1. 导入约束:context约束(xmlns:context="http://www.springframework.org/schema/context")

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

@Autowire

直接在属性上使用即可,也可以在set方法上使用

使用Autowired可以不用编写set方法了,前提是这个自动装配的属性在IOC(Spring)容器中存在(在applicationContext.xml文件中存在)。

@Autowired默认按类型装配(byType)(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配(byName)可以结合@Qualifier注解进行使用,如下:

@Autowired
@Qualifier("window2")
private Window window;

@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

@Resource
private Door door;

@Resource和@Autowired异同

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired默认通过byType的方式实现,且这个bean必须在xml中被配置
  • @Resource默认通过byName的方式实现,如果找不到名字则通过byType实现,如果两个都找不到的情况下才报错
  • 执行顺序不同:@Autowired默认通过byType,@Resource默认通过byName

8、使用注解开发

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

image-20210624224139594

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

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        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>

1、bean

2、属性如何注入

//等价于<bean id="user" class="com.chen.pojo.User"/>
//@Component 组件
@Component
public class User {
    //相当于<property name="name" value="旭旭"/>
    @Value("旭旭")
    public String name;
}

3、衍生注解

@Component有几个衍生注解,我们在web开发中会按照mvc三层架构分层。这四个注解作用是一样的。

  • Dao【@Repository】
  • Service【@Service】
  • Controller【@Controller】

4、自动装配

@Autowired
@Resource
@Nullable 字段标记了这个注解,说明这个字段可以为null

5、作用域

//单例
@Scope("singleton")
public class User
    
//多实例
@Scope("prototype")
public class User

6、小结

xml与注解:

  • xml更加万能,适用于任何场合,维护简单方便
  • 注解:不是自己的类使用不了,维护相对复杂

最佳实践:

  • xml用来管理bean
  • 注解只负责完成属性的注入
  • 在使用的过程中需要注意必须让注解生效,需要开启注解的支持
<!--开启注解的支持-->
<context:annotation-config/>

<!--开启包扫描,指定的包下面的注解就会生效-->
<context:component-scan base-package="com.chen"/>

9、使用java的方式配置Spring

用java类完全替代Spring的xml配置。

JavaConfig是Spring的一个子项目,在Sping4之后它成为一个核心功能。

package com.chen.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//这个注解的意思,说明这个类被Spring接管了,即注册到了容器中
@Component
public class User {
    private int id;

    public int getId() {
        return id;
    }

    //属性注入值
    @Value("12")
    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                '}';
    }
}
package com.chen.config;

import com.chen.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//这个类也会被Spring容器托管,注册到容器中,因为他本身就是被@Component修饰,
// @Configuration代表这是一个配置类,就和applicationContext.xml是一样的
@Configuration
@ComponentScan("com.chen.pojo")//默认不写也是可以扫描的
@Import(MyConfig2.class)//将另一个配置类引入
public class MyConfig {

    //注册一个bean,相当于一个bean标签
    //方法名相当于bean标签中的id属性
    //返回值类型相当于bean标签中的class属性
    @Bean
    public User getUser(){
        //返回要注入到bean的对象
        return new User();
    }

}

import com.chen.config.MyConfig;
import com.chen.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MyTest {
    @Test
    public void test1(){
        //如果完全使用了配置类去做,那就只能通过AnnotationConfig上下文来获取容器,通过配置类的class对象加载
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        User user = (User) context.getBean("getUser");
        System.out.println(user.getId());
    }
}

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

10、代理模式

为什么要学习代理模式?因为这是SpringAOP的底层。【SpringAOP和SpringMVC】

代理模式的分类:

  • 静态代理
  • 动态代理

image-20210629203456313

10.1、静态代理

角色分析:

  • 抽象角色:一般会用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
  • 客户:访问代理对象的人

代码步骤:

  1. 接口

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

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

    public class Proxy {
        private Host host;
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        public Proxy() {
        }
    
        public void rent(){
            seeHouse();
            host.rent();
            sign();
            fare() ;
        }
    
        public void seeHouse(){
            System.out.println("中介带看房");
        }
    
        public void sign(){
            System.out.println("签租租赁合同");
        }
    
        public void fare(){
            System.out.println("收中介费");
        }
    }
    
  4. 客户端访问代理角色

    public class Client {
        public static void main(String[] args) {
            Host host = new Host();
            //代理,中介帮房东租房子,但是中介一般要做一些附加的事
            Proxy proxy = new Proxy(host);
            proxy.rent();
        }
    }
    

代理模式的好处:

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

缺点:

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

10.2、加深理解

聊聊AOP

image-20210629215621994

10.3、动态代理

  • 动态代理和静态代理角色一样(抽象角色,真实角色,代理角色)
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理、基于类的动态代理
    • 基于接口---JDK动态代理
    • 基于类:cglib
    • java字节码:javassist

需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序

动态代理的好处:

  • 动态代理和静态代理角色一样(抽象角色,真实角色,代理角色)
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理、基于类的动态代理
  • 一个动态代理类代理的是一个接口,一般就是对应一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

11、AOP

11.1、什么是AOP

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

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

配置类中加入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">


</beans>

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

  1. 增强的功能想要实现SpringAPI接口(通知)
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {

    //method:要执行的目标对象的方法
    //args:参数
    //target:目标对象
    public void before(Method method, Object[] objects, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被调用了");
    }
}
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {

    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为"+returnValue);
    }
}
  1. 切入点(实现一个接口)
public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}
public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("增加了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }
}
  1. 配置文件
<!--注册bean-->
<bean id="userService" class="com.chen.service.UserServiceImpl"/>
<bean id="log" class="com.chen.log.Log"/>
<bean id="afterLog" class="com.chen.log.AfterLog"/>

<!--方式一:使用SpringAPI原生的接口,功能强大,可以对切入点方法做更多的事情-->
<!--配置aop需要导入aop的约束-->
<aop:config>
    <!--切入点,expression表达式,execution(要执行的位置!)-->
    <aop:pointcut id="pointcut" expression="execution(* com.chen.service.UserServiceImpl.*(..))"/>
    <!--执行环绕增强-->
    <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
  1. 测试
import com.chen.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Mytest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        //动态代理的是接口
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
}

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

  1. 自定义一个切面类
public class DiyPointCut {

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

    public void after(){
        System.out.println("方法执行后");
    }
}
  1. 切入点和方法一一样
  2. 配置
<bean id="diy" class="com.chen.diy.DiyPointCut"/>

<aop:config>
    <!--自定义切面,ref要引用的类-->
    <aop:aspect ref="diy">
        <!--切入点-->
        <aop:pointcut id="point" expression="execution(* com.chen.service.UserServiceImpl.*(..))"/>
        <!--通知-->
        <aop:before method="before" pointcut-ref="point"/>
        <aop:after method="after" pointcut-ref="point"/>
    </aop:aspect>
</aop:config>

方式三:使用注解实现

  1. 开启注解支持

    <!--开启注解支持-->
    <aop:aspectj-autoproxy/>
    
  2. 用注解修饰类和方法

    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    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.chen.service.UserServiceImpl.*(..))")
        public void before(){
            System.out.println("------方法执行前------");
        }
    
        @After("execution(* com.chen.service.UserServiceImpl.*(..))")
        public void after(){
            System.out.println("------方法执行后------");
        }
    
        @Around("execution(* com.chen.service.UserServiceImpl.*(..))")
        public void around(ProceedingJoinPoint pj) throws Throwable {
            System.out.println("------环绕前------");
            //获得签名
            Signature signature = pj.getSignature();
            System.out.println("Signature"+signature);
            //执行方法
            Object proceed = pj.proceed();
            System.out.println("------环绕后------");
        }
    }
    
  3. 配置

<!--方式三:使用注解-->
<bean id="annotationPointCut" class="com.chen.diy.AnnotationPointCut"/>

12、整合Mybatis

步骤

  1. 导入相关jar包

    • junit
    • mybatis
    • mysql数据库
    • spring相关的
    • aop织入
    • mybatis-spring
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>spring-study</artifactId>
            <groupId>com.chen</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>spring-10-mybatis</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.2</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>5.2.0.RELEASE</version>
            </dependency>
            <!--Spring操作数据库需要一个spring-jdbc-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.3.7</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.7</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>2.0.2</version>
            </dependency>
        </dependencies>
    </project>
    
  2. 编写配置文件

  3. 测试

posted @ 2021-07-27 22:07  补拙  阅读(166)  评论(0)    收藏  举报