Loading

狂神说-Spring

1、Spring

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

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

1.1、优点:

  • Spring是一个开源的免费的框架(容器)!

  • Spring是一个轻量级的、非入侵式的框架!

  • 控制反转(IOC) ,面向切面编程(AOP)!

  • 支持事务的处理,对框架整合的支持!

1.2、组成

image-20220315210045608

  • Spring Boot

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

    • SpringCloud是基于SpringBoot实现的。

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

1.3、配置

Maven依赖:

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

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

</beans>

2、IOC理论推导

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

我们使用一个Set接口实现,已经发生了革命性的变化

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

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

IOC本质

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

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

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

3、HelloSpring

3.1、实体类

package com.gao.pojo;

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 + '\'' +
                '}';
    }
}

3.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    使用Spring来创建对象,在Spring这些都称为bean

        类型 变量名 = new 类型()
        Hello hello = new Hello()

        id = 变量名
        class = new 的对象
        property 相当于给对象中的属性设置一个值
        value : 具体的值,基本数据类型
        ref : 引用Spring容器中创建好的对象
-->
    <bean id="hello" class="com.gao.pojo.Hello">
        <property name="str" value="gao"/>
    </bean>

</beans>

3.3、测试类

import com.gao.pojo.Hello;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void getHello(){
        //获取Spring的上下文对象
        //获取ApplicationContext,拿到Spring的容器
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Hello hello = (Hello) context.getBean("hello");
        System.out.println(hello.toString());
    }
}
  • Hello 对象是谁创建的?

    hello对象是由Spring创建的

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

    hello对象的属性是由Spring容器设置的,

这个过程就叫控制反转︰

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

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

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

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

可以通过newClassPathXmlApplicationContext去浏览一下底层源码.

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

4、IOC创建对象的方式

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

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

    1. 下标赋值
    <bean id="hello" class="com.gao.pojo.Hello">
        <constructor-arg index="0" value="xy"/>
    </bean>
    
    1. 类型
    <bean id="hello" class="com.gao.pojo.Hello">
        <constructor-arg type = "java.lang.String" value="xy"/>
    </bean>
    
    1. 参数名
    <bean id="hello" class="com.gao.pojo.Hello">
        <constructor-arg name = "str" value="xy"/>
    </bean>
    

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

5、Spring配置

5.1、别名

<!--    别名:如果设置了别名,我们也可以通过别名获取到对象-->
    <alias name="hello" alias="gao"/>

5.2、Bean的配置

<!--    id : bean的唯一标识符,也就是相当于我们学的对象名
        class : bean对象所对应的全限定名:包名+类型
        name :也是别名,而且name可以同时取多个别名
-->
    <bean id="hello" class="com.gao.pojo.Hello" name="h1 h2,h3;h4">
        <constructor-arg name = "str" value="xy"/>
    </bean>

5.3、import

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

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的

  • applicationContext
<import resource="bean1.xml"/>
<import resource="bean2.xml"/>
<import resource="bean3.xml"/>

使用时,直接使用总配置即可

6、依赖注入

6.1、构造器注入

见第4点

6.2、Set方式注入【重点】

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

环境搭建

1、复杂类型

package com.gao.pojo;

public class Address {
    private String address;

    public String getAddress() {
        return address;
    }

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

2、真实测试对象

package com.gao.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 String wifi;
    private Properties info;

    public String getName() {
        return name;
    }

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

    public Address getAddress() {
        return address;
    }

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

    public String[] getBooks() {
        return books;
    }

    public void setBooks(String[] books) {
        this.books = books;
    }

    public List<String> getHobbys() {
        return hobbys;
    }

    public void setHobbys(List<String> hobbys) {
        this.hobbys = hobbys;
    }

    public Map<String, String> getCard() {
        return card;
    }

    public void setCard(Map<String, String> card) {
        this.card = card;
    }

    public Set<String> getGames() {
        return games;
    }

    public void setGames(Set<String> games) {
        this.games = games;
    }

    public String getWifi() {
        return wifi;
    }

    public void setWifi(String wifi) {
        this.wifi = wifi;
    }

    public Properties getInfo() {
        return info;
    }

    public void setInfo(Properties info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", address=" + address +
                ", books=" + Arrays.toString(books) +
                ", hobbys=" + hobbys +
                ", card=" + card +
                ", games=" + games +
                ", wifi='" + wifi + '\'' +
                ", info=" + 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.gao.pojo.Student">
        <property name="name" value="张三"/>
    </bean>
</beans>

4、测试类

import com.gao.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void getStudent(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }
}

5、完善注入

    <bean id="address" class="com.gao.pojo.Address">
        <property name="address" value="上海"/>
    </bean>
    <bean id="student" class="com.gao.pojo.Student">
<!--        第一种,普通注入-->
        <property name="name" value="张三"/>
<!--        第二种 bean注入-->
        <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>LOL</value>
            </list>
        </property>
<!--        Map-->
        <property name="card">
            <map>
                <entry key="姓名" value="张三"/>
                <entry key="学号" value="20200101"/>
            </map>
        </property>
<!--        Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>原神</value>
                <value>王者荣耀</value>
            </set>
        </property>
<!--        null-->
        <property name="wifi">
            <null/>
        </property>
<!--        Properties-->
        <property name="info">
            <props>
                <prop key="driver">mysql</prop>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>

6.3、拓展方式注入

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

官方解释:

<!--p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" c1ass="com.kuang.pojo.user" p:name="李四" p:age="18"/>
<!--c命名空间注入,通过构造器注入:construct-args-->
<bean id="user2" class="com.kuang.pojo.user" c:age="18" c:name="王五"/>

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

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

6.4、bean的作用域

Scope Description
singleton (默认)将单个 bean 定义限定为每个 Spring IoC 的单个对象实例 容器
prototype 将单个 bean 定义限定为任意数量的对象实例。
request 将单个 bean 定义限定为单个 HTTP 请求的生命周期。 那是, 每个 HTTP 请求都有自己的 bean 实例,该实例是在单个 bean 的背面创建的 定义。 仅在 Web 感知 Spring 的上下文中有效 ApplicationContext.
session 将单个 bean 定义限定为 HTTP 的生命周期 Session. 仅适用于 Web 感知 Spring 的上下文 ApplicationContext.
application 将单个 bean 定义限定为 ServletContext. 仅适用于 Web 感知 Spring 的上下文 ApplicationContext.
websocket 将单个 bean 定义限定为 WebSocket. 仅适用于 Web 感知 Spring 的上下文 ApplicationContext.
  1. 测试代码
@Test
public void getUser(){
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    User user = context.getBean("user", User.class);
    User user1 = context.getBean("user", User.class);
    System.out.println(user==user1);
}
  1. 单例模式(Spring默认机制)
<bean id="user" class="com.gao.pojo.User" p:name="张三" p:age="18" scope="singleton"/>

测试结果:true
  1. 原型模式,每次从容器中get的时候,都会产生一个新对象
<bean id="user" class="com.gao.pojo.User" p:name="张三" p:age="18" scope="prototype"/>

测试结果:false
  1. 其余的request、session、application这些只能在web开发中用到

7、Bean的自动装配

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

在Spring中有三种装配的方式

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

7.1、ByName自动装配

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

7.2、ByType自动装配

<bean class="com. kuang.pojo.cat" />
<bean class="com. kuang.pojo.Dog" />
<!--
    byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid!
    byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean !
-->
<bean id="people" class="com. kuang.pojo.Peop1e" autowire="byType ">
<property name="name" value="张三"/>
</bean>I

小结:

  • byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!

  • bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

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

使用注解须知:

  1. 导入约束: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-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我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byname

科普:

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

如果显示定义了Autowired的required属性为false,说明这个对象可以为nu11,否则不允许为空

public class People {
//如果显示定义了Autowired的required属性为fa1se,说明这个对象可以为nu11,否则不允许为空
    @Autowired(required = false)
    private cat cat;
    @Autowired
    private Dog dog;private string name;
}

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

public class People {
@Autowired
@Qualifier(value="cat111")
    private cat cat;
@Autowired
@Qualifier(value="dog222")
    private Dog dog; 
	private string name;
}

@Resource注解(新版可能没有这个注释)

public class People {
@Resource(name = "cat2")
    private cat cat;
@Resource
private Dog dog;
}

小结:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • Autowired通过byType的方式实现,而且必须要求这个对象存在!【常用】
  • Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现!如果两个都找不到的情况下,就报错!【常用】
  • 执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过byname的方式实现

8、使用注解开发

1、bean

xml文件中:

<context:component-scan base-package="com.gao"/>
<context:annotation-config/>

Java:

//这里这个注解的意思,就是说明这个类被Spring接管了,注册到了容器中
@Component
public class User {}

2、属性如何注入

@Component
public class User {
    //相当于<property name="name" value="gao"/>
    @Value("gao")
    private String name;

    public String getName() {
        return name;
    }

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

3、衍生的注解

​ @Component有几个衍生的注解,我们在web开发中,会按照mvc三层架构进行分层

  • dao
  • service
  • controller

4、自动装配置

@Autowired :自动装配通过类型。名字
如果Autowired不能唯一自动装配上属性,则需要通过@Qualifier(value="xxx")@Nullable字段标记了这个注解,说明这个字段可以为null;
@Resource:自动装配通过名字。类型。

5、作用域

@Component
@Scope("singleton")
public class User {
    //相当于<property name="name" value="gao"/>
    @Value("gao")
    private String name;

    public String getName() {
        return name;
    }

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

6、小结

xml与注解:

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

xml与注解最佳实践:

  • xml 用来管理bean;

  • 注解只负责完成属性的注入;

  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持

    <!--扫描指定要扫描的包,这个包下的注解就会生效-->
    <context:component-scan base-package="com.gao"/>
    <context:annotation-config/>
    

9、使用Java的方式配置Spring

实体类

@Component
public class User {
    //相当于<property name="name" value="gao"/>
    @Value("gao")
    private String name;

    public String getName() {
        return name;
    }

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

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

配置文件

package com.gao.config;

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

//这个也会Spring容器托管,注册到容器中,因为他本来就是一个@Component
// @Configuration代表这是一个配置类,就和我们之前看的beans.xmL
@Configuration
@ComponentScan("com.gao.pojo")
@Import(Config2.class)
public class Config {

    //注册一个bean .就相当于我们之前写的一个bean标签
    //这个方法的名字,就相当于bean标签中的id属性
    //这个方法的返回值,就相当于 bean标签中的cLass属性
    public User getUser(){
        return new User();
    }
}

测试类

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

10、代理模式

SpringAOP的底层【SpringAOP 和 SpringMVC】

代理模式的分类:

  • 静态代理
  • 动态代理

image-20220319171718088

10.1、静态代理

角色分析:

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

代码步骤:

  1. 接口

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

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

    public class Agent implements Rent{
        private landlord ld;
    
        public Agent(landlord ld) {
            this.ld = ld;
        }
    
        @Override
        public void rent() {
            ld.rent();
            seeHouse();
        }
    
        public void seeHouse(){
            System.out.println("中介带你看房");
        }
    }
    
  4. 客户端访问代理角色

    public class Client {
        public static void main(String[] args) {
            landlord ld=new landlord();
            Agent agent = new Agent(ld);
            agent.rent();
        }
    }
    

代理模式的好处:

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

缺点:

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

10.2、AOP

image-20220319195051442

10.3、动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理。
    • 基于接口---JDK动态代理【我们在这里使用】
    • 基于类: cglib
    • java字节码实现: javasist

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

接口

public interface UserService {
    public void add();
    public void update();
    public void query();
    public void delete();
}

接口实现类

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

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

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }

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

动态代理实现方法【重点】

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandle implements InvocationHandler {
    //被代理的接口
    Object target = new Object();

    public void setTarget(Object target){
        this.target = target;
    }

    //得到代理类
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(), this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        Object result = method.invoke(target,args);
        return result;
    }

    public void log(String msg){
        System.out.println("执行了" +msg+ "方法");
    }
}

测试类

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色,不存在
        ProxyInvocationHandle pih = new ProxyInvocationHandle();
        pih.setTarget(userService);
        UserService proxy = (UserService) pih.getProxy();
        proxy.add();
        proxy.delete();
        proxy.query();
        proxy.update();
    }
}

动态代理的好处:

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

11、AOP

11.1、什么是AOP

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

image-20220320122612524

AOP在Spring中的作用:提供声明式事务,允许用户自定义切面

11.2、使用Spring实现AOP

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

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

方式一:使用Spring的API接口

接口

public interface UserService {
    public void add();
    public void update();
    public void query();
    public void delete();
}

接口实现类

public class UserServiceImpl implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

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

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }

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

前置日志类

public class BeforeLog implements MethodBeforeAdvice {

    //method: 要执行的目标对象的方法
    //args: 参数
    //target: 目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName() +"的"+ method.getName() + "被执行了");
    }
}

后置日志类

public class AfterLog implements AfterReturningAdvice {

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

配置文件

    <bean id="beforeLog" class="com.gao.log.BeforeLog"/>
    <bean id="afterLog" class="com.gao.log.AfterLog"/>
    <bean id="user" class="com.gao.service.UserServiceImpl"/>
<!--    配置aop,需要导入aop的原生接口-->
    <aop:config>
<!--        切入点:expression:表达式,execution(要执行的位置!* * * * *)-->
        <aop:pointcut id="pointcut" expression="execution(* com.gao.service.UserServiceImpl.*(..))"/>
<!--        执行环绕增加-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    </aop:config>

测试类

@Test
public void getUser(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    UserService user = context.getBean("user", UserService.class);
    user.add();
}

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

自定义类

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

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

配置文件

<!--    方式二:自定义类-->
    <bean id="diy" class="com.gao.diy.DiyPointCut"/>
    <aop:config>
<!--        自定义切面,ref:要引用的类-->
        <aop:aspect ref="diy">
            <aop:pointcut id="point" expression="execution(* com.gao.service.UserServiceImpl.*(..))"/>
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        </aop:aspect>
    </aop:config>

方式三:注解实现

注解类

@Aspect //标注这个类是一个注解切面
public class AnnotationPointCut {
    @Before("execution(* com.gao.service.UserServiceImpl.*(..))")
    public void Before(){
        System.out.println("=============方法执行前============");
    }
    @After("execution(* com.gao.service.UserServiceImpl.*(..))")
    public void After(){
        System.out.println("=============方法执行后============");
    }
    //在环绕增强中,我们可以给定一个参数,代表我们要获取处理切入的点
    @Around("execution(* com.gao.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        Object proceed = jp.proceed();
        System.out.println("环绕后");
    }
}

配置文件

<bean id="apc" class="com.gao.diy.AnnotationPointCut"/>
<aop:aspectj-autoproxy/>

12、整合Mybatis

步骤:

1、导入相关jar包

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.19.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.9</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.16</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.8</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.7</version>
    </dependency>
</dependencies>

实体类

package com.gao.pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

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

UserMapper

public interface UserMapper {
    List<User> getUser();
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.gao.mapper.UserMapper">
    <select id="getUser" resultType="User">
        select * from user
    </select>
</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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    DataSource:使用Spring的数据源替换Mybatis的配置  c3p0 dbcp druid-->
<!--    这里使用Spring提供的JDBC: rg.springframework.jdbc.datasource-->
    <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?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSl=true"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>
<!--    sqlSessionFactory-->
    <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/gao/mapper/UserMapper.xml"/>
    </bean>
<!--    SqlSessionTemplate:就是我们使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--        只能使用构造器注入sqlSessionFactory,因为没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    
<!--        下面的部分可以单独拿出来做一个配置文件,上面的部分属于不动部分-->
    <bean id="userMapperImpl" class="com.gao.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

mybatis-config.xml(可直接不写,都由Spring进行配置)

<?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核心配置文件-->
<!--在这里 &amp;  等价于 &-->
<configuration>
    <typeAliases>
        <typeAlias type="com.gao.pojo.User" alias="User"/>
    </typeAliases>

</configuration>

UserMapperImpl

public class UserMapperImpl implements UserMapper{
    private SqlSessionTemplate sqlSession;
    public void setSqlSession(SqlSessionTemplate sqlSession){
        this.sqlSession = sqlSession;
    }
    @Override
    public List<User> getUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.getUser();
    }
}

测试类

public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper userMapper = context.getBean("userMapperImpl", UserMapper.class);
        for (User user : userMapper.getUser()) {
            System.out.println(user);
        }
    }
}

方式二

UserMapperImpl2

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> getUser() {
        return getSqlSession().getMapper(UserMapper.class).getUser();
    }
}

配置文件

<bean id="userMapperImpl2" class="com.gao.mapper.UserMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

通过实现SqlSessionDaoSupport的方式,省去了SqlSessionTemplate对象的创建,直接调用getSqlSession()方法即可,在配置文件中只需要对UserMapperImpl2类注入sqlSessionFactory即可,可以省去sqlSession的相关配置

13、声明式事务

UserMapper

public interface UserMapper {
    List<User> getUser();
    int addUser(User user);
    int deleteUser(int i);
}

UserMapperImpl2.xml

public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> getUser() {
        User user = new User(4,"赵六","564564");
        addUser(user);
        deleteUser(5);
        return getSqlSession().getMapper(UserMapper.class).getUser();
    }

    @Override
    public int addUser(User user) {
        return getSqlSession().getMapper(UserMapper.class).addUser(user);
    }

    @Override
    public int deleteUser(int i) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(i);
    }
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.gao.mapper.UserMapper">
    <select id="getUser" resultType="User">
        select * from user
    </select>

    <insert id="addUser" parameterType="User">
        insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>

    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>
</mapper>

配置文件(新增)

<!--    配置声明式事务-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<!--    结合AOP实现事务的织入-->
<!--    配置事务通知-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--        给哪些方法配置事务-->
<!--        配置事务的传播特性,propagation默认为REQUIRED-->
        <tx:attributes>
            <tx:method name="addUser" propagation="REQUIRED"/>
            <tx:method name="deleteUser"/>
            <tx:method name="getUser"/>
        </tx:attributes>
    </tx:advice>
<!--    配置事务切入-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(* com.gao.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
posted @ 2022-03-29 14:34  -天气之子-  阅读(88)  评论(0编辑  收藏  举报