Spring5轻轻松松一遍过

134 阅读16分钟

「时光不负,创作不停,本文正在参加2021年终总结征文大赛

前言

在此之前我先谈谈我的学习路线,我个人感觉是有点飘,不太可取的,但是也说明一下我为什么直接跳过Java 的 web基础,也就是severlet 和 jsp这一块,直接上spring全家桶而且上的时候还是先从Dao层也就是 mybatis 和 mybatis-plus( 主要)这一块开始哈。首先如果你一开始就关注了我,也就是我从高二开始的时候第一次从CSDN发布了博客,那个时候我是在玩爬虫的,对于很多的请求库和网络请求的一些细节和网站运作我是有一定了解的,当然那个时候我更多的技术倾向是发送请求,爬虫反反爬,请求参数抓取,爬虫稳定,爬取效率这一块。当然高三那一年没怎么玩了毕竟学习嘛,后来大一我一个学期玩的是网络安全相关的东西,当然也是接触了很多奇奇怪怪的东西,这一块我暂时没有深挖下去,因为第一是面向监狱编程不可取,二是遇到了瓶颈,我发现我一个学期下来都还只是在玩玩框架,对于想要渗透的对象一无所知(并不是很清楚),我没有去理解底层(当然现在也没有),只知道这个怎么用,至于为什么这样我回答的很模棱两可。后来就是玩了玩Java一开始就是玩玩安卓,哪个感兴趣我玩哪个,我没有按照网上给的路线走,然后嘛,后面都出鸿蒙了是吧.......客户端还是不太稳的而且太考验美感了!之后就是我又回到了python 路线,当时学的还算认真 起码手撸了一个 Http 服务器(不过那是寒假就发生的事情了,我重新捡起的时候是暑假了)然后就是恶补前面的内容然后上Django,随便研究了一下Django可能存在的问题(渗透),再后来就是数学建模比赛了,我暂时就停止了(其实当时也差不多了只是我本来打算做个网站的只是暂时停了)。之后大二回到学校我忙完了一些事情,不过都一个月了国庆的时候紧急花了五天做出了一个whitehole,当然也停了,现在是打算赶紧学然后用Java重构,之后再在两个框架之间不断更新完善。所以在基础方面我自认为我是可以跳的,大不了补回来呗。然后就是我目前选择的搭配就是 Spring springboot mybatisplus 至于mvc慢慢来看看呗,玩框架不谈设计思想只谈承上启下我觉得是很可笑的,至于底层很多人所谓的底层是另一个框架(搞不懂 手动狗头)......

Spring简介

记住两句话 1.前身 interface21 在 2002 年推出 2.控制反转(IOC) 和 面向切面(AOP) 其他的就不说了,我也记不住! 那么我们这块就先说说啥叫 IOC 和 AOP

何为AOP

首先AOP这玩意老盆友了,不管是Java还是python天天用! 这边我都有博客说明!

Java Dome(AOP模式回顾小Dome) @高级语法python(装饰器)语法小糖豆。

何为IOC

set注入

在此之前先来谈谈注入(开发模式)这个是IOC的前身。 咱们直接演示代码吧,老套路了一看就会。 举个例子: 模拟点菜,在现实生活中点菜的时候有一个菜单,菜单时固定的,但是厨师不是.现在菜单就好比接口,不会轻易变动,但是厨师却可以不断变动.现在假设有两个厨师,都会做菜单上的菜.然后顾客可以随意跟换厨师做菜.

菜单接口:`

public interface Foodmean {
	void chaojidan();
	void chaoxihongshi();
}

厨师类实现接口功能

1.AmericanCook

public class AmericanCook implements Foodmean{
	public void chaojidan(){
		System.out.println("AmericanCook is cooking chaojidan");
	}
	public void chaoxihongshi(){
		System.out.println("AmericanCook is cooking chaoxihongshi");
	}
}

2.ChineseCook

public  class Chinesecook implements Foodmean {
	public void chaojidan(){
		System.out.println("ChineseCook is cooking chaojidan");
	}
	public void chaoxihongshi(){
		System.out.println("ChineseCook is cooking chaoxihongshi");
	}

}

顾客类 这里的话当然少不了Food mean 其实接口的使用往往和多态离不开

public class Customer {
	private Foodmean foodmean;
	
	public Customer(){
		
	}
	public Customer(Foodmean foodmean){
		this.foodmean = foodmean;
	}
	public Foodmean getFoodmean() {
		return foodmean;
	}
	public void setFoodmean(Foodmean foodmean) {
		this.foodmean = foodmean;
	}
	public void order(){
		this.foodmean.chaojidan();
		this.foodmean.chaoxihongshi();
	}
}

调用测试:

public class Text {

	public static void main(String[] args) {
//		Foodmean foodmean = new AmericanCook();
		Foodmean foodmean = new Chinesecook();
 		Customer xiaomingCustomer=new Customer();
		xiaomingCustomer.setFoodmean(foodmean);
		xiaomingCustomer.order();
	}
}

现在换一下

Foodmean foodmean = new AmericanCook();

这个就是我们经常用的(新手时期) 那么后面IOC是啥呢,就是这样: 我们再定义一个类

public class Cooker{
	private Foodmean foodmean;
	
	public void setMean(Foodmean foodmean){
	this.foodmean = foodmean;
}
	public Foodmean getMean(){
	return this.foodmean;}
}

那么接下来我们的Test就这样写

public class Text {

	public static void main(String[] args) {
		Cooker cooker  = new Cooker();
 		Customer xiaomingCustomer=new Customer();
		xiaomingCustomer.setFoodmean(cooker.setMean(new Chinesecook()));
		xiaomingCustomer.order();
	}
}

那么现在你想要哪个就new 哪一个。并且这里并不是直接去new一个而是通过了第三方!

IOC本质

那么这个就是所谓的反转,所谓的IOC,一直设计思想。顺转是什么那就是控制权在我们手上。那这句话又怎么理解呢,也就是先前我们是直接要用哪个直接New 一个,但是现在我们使用了一个第三方提供了一个set方法,我们这个时候就只需要通过它来换对应的实现,一方面我们可以解耦合,另一方面在一定程度下可以动态的切换模式,例如功能切换之类的。这个其实没啥好说的了,哪一次的我做的小玩意我没用过这种类型的设计思想(只是我当初不知道叫啥!)在总结一句话那就是依赖转移!,前面的什么set那个叫做依赖注入(DI注入),所谓的依赖就是需求,需要new哪一个类

那么这个Spring的IOC容器是啥,一句话总结若干个符合业务的类似于前面例子Cooker类的集合然后再结合我们的工厂模式和注解或者xml去方便调用实现。很高级看起来! 那么这边在Spring实现是通过xml或者注解实现的。这边我忘了写一篇如何结合AOP模式手撸一个注解的博文了,有需要评论区留言。

Spring Hello world

ok,先说明一下啊Spring只是做个了解罢了,过一遍而已。 创建Maven项目导入依赖,就不用多说了吧。

<?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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringFrame</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-dome-01</module>
    </modules>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

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

</project>

然后干啥创建写个Hello world

package com.huterox.pojo;

public class Hello {
    private String Hello;

    public String getHello() {

        return Hello;
    }

    public void setHello(String hello) {
        Hello = hello;
    }

    public Hello(String hello) {
        Hello = hello;
    }

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

这个文件放在哪不用多说了吧。 然后是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 http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="Hello" class="com.huterox.pojo.Hello">
        <constructor-arg value=""/>
        <property name="Hello" value="Hello world"/>
       
                
    </bean>
<!--    <bean id="Hello" class="com.huterox.pojo.Hello"/> 不赋值只是注册-->
<!--        <property name="Hello" value="Hello world"/> ref="具体对象名,bean的id名字"-->

</beans>

在这里插入图片描述

然后进入测试

import com.huterox.pojo.Hello;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {

   public static void main(String[] args) {
       ClassPathXmlApplicationContext Context = new ClassPathXmlApplicationContext("Aplication.xml");
       Hello hello = (Hello) Context.getBean("Hello");
       System.out.println(hello.getHello());

   }
}

突然发现这个套路和安卓挺像的。 至于他为什么能够实现的原理嘛,其实很简单的,看前面那个AOP的那个博客你就能搞明白,只不过这里换了一下xml文件,这个xml文件怎么搞也很简单,有需要评论区说明,看心情更新。当然那只是原理,实现起来它分了很多层。

Hello world 细节

IOC创建对象

我们这边其实就是一个IOC的演示在Spring,那么在这里的话注意到配置文件

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

    <bean id="Hello" class="com.huterox.pojo.Hello">
        <constructor-arg value=""/>
        <property name="Hello" value="Hello world"/>
       
                
    </bean>
<!--    <bean id="Hello" class="com.huterox.pojo.Hello"/> 不赋值只是注册-->
<!--        <property name="Hello" value="Hello world"/> ref="具体对象名,bean的id名字"-->

</beans>

这里有两个注意点

对象赋值

这个通过

<property name="Hello" value="Hello world"/>

来实现

对象构造方法赋值

<constructor-arg value=""/>

这里有三种方式给值。 1.下标

<constructor-arg index="0" value=""/>

2 . 变量属性

<constructor-arg type="int" value=""/>
<constructor-arg type="java.lang.String" value=""/>

3.变量名直接赋值

<constructor-arg name="Hello" value="Hello world"/>

getBean创建对象细节

这个其实在加载配置文件的时候会把所有的对象都进行创建,也就是说在加载配置文件的时候里面所有的注册了的类都会被实例化,之后通过getbean方法获取其中某一个。 此外getbean获取相同的对象时获取的是同一个对象。

        ClassPathXmlApplicationContext Context = new ClassPathXmlApplicationContext("Aplication.xml");
        Hello hello = (Hello) Context.getBean("Hello");
        Hello hello1 = (Hello) Context.getBean("Hello");
        System.out.println(hello==hello1);
        

这个值为真 ,那原因的话是因为我们目前使用的是单例模式。(这个可以改)

Spring 配置

取别名 alias

这个Linux玩多了的老熟了。 这个简单回到那个配置文件

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

    <bean id="Hello" class="com.huterox.pojo.Hello">
        <constructor-arg value=""/>
        <property name="Hello" value="Hello world"/>
       
                
    </bean>
    <alias name="Hello" alias="H"/>
    <!-- 把 Hello 别名为 H 到时候直接读取 H 也是一样的 -->
<!--    <bean id="Hello" class="com.huterox.pojo.Hello"/> 不赋值只是注册-->
<!--        <property name="Hello" value="Hello world"/> ref="具体对象名,bean的id名字"-->

</beans>

Bean

这个就不用多说了,前面都演示多少回了 这里补充一下

<bean id="Hello" class="com.huterox.pojo.Hello" name="H“>

这里name直接取别名

<bean id="Hello" class="com.huterox.pojo.Hello" name="H,W“>

取多个别名,H ,W 可以用 ,和 空格 分号 分隔别名

import

导入多个配置文件参考 nginx的 include

<import resource="beans.xml"/>

这个就好了,如果导入的文件的bean有重复的话他会自己选择一个所以注意重复问题,取个好点的别名。

注入详谈

这个注入前面也铺垫了。什么是注入也应该看明白了。 不过前面没有好好说清楚,那么在这里就详细说一说,咱们这个主要是啥,是值注入,也就是针对变量赋值。 现在咱们定义一个类,现在依次通过xml进行赋值

public class UserDomeValue {
    private String name;
    private String[] strings;
    private List<String> list;
    private Set<String> set;
    private Properties properties;
    private Map<String,String> map;

}

基础类型注入

<property name="name" value="UserDome"/>
       

Map注入

  <property name="map">
            <map>
                <entry key="Hello" value="world"/>
            </map>
        </property>
        

数组注入

<property name="strings">
            <array>
                <value>Hello</value>
                <value>world</value>
            </array>
        </property>

列表注入

 <property name="list">
            <list>
                <value>Hello</value>
                <value>World</value>
            </list>
        </property>

集合注入

  <property name="set">
            <set>
                <value>Hello</value>
                <value>world</value>
            </set>
        </property>

Properties注入

 <property name="properties">
            <props>
                <prop key="Hello">world</prop>
            </props>
        </property>

优化配置

对于一些简单的注入我们还有更加好的选择,那就是P命名和C命名空间注入。 这个其实很简单,一个是针对参数的一个是针对构造方法传值的。 先导入两个玩意

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

那么现在直接看到这个 在这里插入图片描述 看到了不直接出来了。 这个用法很简单的,无非就是简化了一下。不用也可以就像先前的Django里面的Q对象。

Bean的作用域

当前基础我们就关注两个,单例,和原型模式。 在这里插入图片描述

单例模式(默认的) 在这里插入图片描述 xml <bean id="Hello" class="com.huterox.pojo.Hello" scope="singleton">

原型模式 在这里插入图片描述 xml <bean id="Hello" class="com.huterox.pojo.Hello" scope="prototype">

自动装配

使用XML自动装配

这玩意咋说呢,就是让Spring自己去根据上下文去寻找对应的值,然后去自己装配,也就是自动赋值,自动帮助我们完成赋值的工作不过这个显然只是适应于简单的操作。 根据名字自动装配。 xml <bean id="Hello" class="com.huterox.pojo.Hello" scope="prototype" autowire="byName"> 根据类型装配 xml <bean id="Hello" class="com.huterox.pojo.Hello" scope="prototype" autowire="byType"> 下面给出例子:

public class Head{}
public class Foot{}
public People{
	private Head head;
	private Foot foot;
	//get set方法省略
}

接下来在xml注册

  <bean id="head" class="com.huterox.pojo.Head"  >
  <bean id="foot" class="com.huterox.pojo.Foot" >
  <bean id="people" class="com.huterox.pojo.People" autowire="byName">

那么此时就会自动装配了,这里是byname所以bean的id的值和people里面的变量的值相同,如果不同就装不了。 例如

 <bean id="head123" class="com.huterox.pojo.Head"  >

此时就不行了。那么除此之外还可以通过注解实现。

Spring 注解

回到我们的XML配置问价,我们需要加入几个依赖。 完整的配置如下

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

  <context:annotation-config/>
  <!--    开启注解支持-->
    
  <bean id="head" class="com.huterox.pojo.Head"  >
  <bean id="foot" class="com.huterox.pojo.Foot" >
  <bean id="people" class="com.huterox.pojo.People">
</beans>

注解自动装配(Autowired)

这个时候咱们回到那个People类

public People{
	@Autowired
	private Head head;
	@Autowired(required=false)
	private Foot foot;
	//表示这个玩意可以为空和下面的等价
	//public void setFoot(@Nullable Foot foot){
	//this.foot = foot;}
	//get set方法省略


}

不过这个也是有局限的,那就是老规矩被装配的bean的id需要和变量名一样(或者说能够找到)(需要装配的) 如果实在找不到还可以给个默认值

public People{
	@Autowired
	private Head head;
	@Autowired(required=false)
	@Qualifier(value="foot")
	private Foot foot;
	//表示这个玩意可以为空和下面的等价
	//public void setFoot(@Nullable Foot foot){
	//this.foot = foot;}
	//get set方法省略


}

所以在用这个的时候请注意环境!如果自动装配环境复杂就挂了。 那么与之类似的还有一个注解这个是Java自己的玩意不是Spring里面的,没有Spring环境也能用

@Rescurce
private Head head;
@Rescurce(name="head")//对应ID的值
private Head head;

区别是 Autowired 是默认通过bytype来实现的。 Rescource 是byname 和 bytyple(byname找不到时)实现的。

基本注解

现在回到前面的配置文件,现在如果我们想要让我们的其他的注解生效那么我们还要一个玩意(除了AOP上下文)看到配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/beans/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/beans/spring-aop.xsd
">
	
  <context:component-scan base-package="com.huterox.pojo"/>  <!-- 需要扫描注解的包-->
  <context:annotation-config/>  <!--    开启注解支持-->
</beans>

Component

这个注解的作用是啥呢那简单举个例子。

@Component
public class Head{}
@Component
public class Foot{}
@Component
public People{
	private Head head;
	private Foot foot;
	//get set方法省略
}

等价于

  <bean id="head" class="com.huterox.pojo.Head"  >
  <bean id="foot" class="com.huterox.pojo.Foot" >
  <bean id="people" class="com.huterox.pojo.People">

id名字默认时类名的小写。 调用还是老规矩。


public class Test {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext Context = new ClassPathXmlApplicationContext("Aplication.xml");
        Hello hello = (People) Context.getBean("people");
        System.out.println(hello.getHello());

    }
}

衍生注解

这个主要时配合spring MVC三层架构的,功能和Component一样的,只是为了好区分。不过我这边 MVC大概率直接跳过,上Spring Boot,搞前后端分离所以后面我会重新学一下vue,MVC或者MVT看了人家的开发发现这样做是真的慢,而且耦合度太高!参考目White Hole 项目 .

三层架构嘛 Dao 层----> @Repository Service ----> @Service controller ----> @Controller 功能一样但是为了区分嘛!

Value

这个是啥呢,就是给默认值。

@Component
public class User{
	@Value("Huterox")
	public String name;
}

对于简单的还是好用的。

Scope注解

这个干啥的不就是单例模式和多例模式嘛

@Component
@Scope("prototype")
//@Scope("singleton")
public class User{
	@Value("Huterox")
	public String name;
}

一般还是给值注入用注解吧,基础的可以用用注解,但是那个xml确实还是永远的神!

JavaConfig

这个是一个比较厉害的地方,官方说是不用依赖配置文件了。 不过这个玩意其实早就见过了,如果你看了前面的博文的话(我是直接先干Dao层的)我用mybatis plus的时候用了一个玩意叫做配置类。 MybatisPlus实现基本CURD&逻辑删除&代码生成(对标Django系列学习二) 不过这玩意还好挺简单的(其实我当时也没注意) 而且这玩意可是好玩多了。 看好了! 首先咱们老规矩搞个类叫User

@Component
public class User(){
	@Value("Huterox")
	private String name;
	//这里省略的get set方法
}

接下来是配置类

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

现在咱们获取这个类

public class MyTest{
	public static void main(String[] args){
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
	User user = (User)context.getBean("getUser");
	}
}

在这里先前还提到了目录扫描,那么在这里也是一样的有

@ComponentScan("com.Huterox.pojo")

此外我们也支持Import引入另一个配置类,这个效果是和我们的配置文件的导入类似的。

@Configuration
@ComponentScan("com.Huterox.pojo")
@Import(Config2.class)
public class Config{
	@Bean
	public User getUser(){
		return new User();
	}
}

这个中方式的话在spring boot好像挺常见的,至少在我先前玩mybatis plus的时候见了不少,基本上我就改了两个东西,一个是spring boot自己的配置文件,还有一个就是配置类。(不得不说我当时是真的刚,啥也不理解就开始怼,不过其实也没啥说白了玩的只是一个框架,暂时不清楚咱们按照规则来就好了,理解一下规则的规律就好了,有时间再补个票,像现在这样,而且现在说实话也不是了解真正的底层,这个不过是引入规则的规则罢了,也就是上级,再挖再挖再挖下去就是计算机底层了,这个没意义,咱们要学的还是框架咋个玩,怎么完好,相关的设计模式和核心思想)

Spring AOP

这个是Spring的一个比较重要的点,其实不管是Java还是python你要做个好玩的东西都用得到,只是在python里面实现这个相当简单,python装饰器了解一下,那么在Java当作其实页挺简单的,那么在spring当中实现这个也很简单,当然这个不需要像我们先前那样从InvocationHandler 工厂模式那里开始撸。

这里面怼几个概念

切面(ASPECT) 通知(Advice) 目标(Target) 代理(Proxy) 切入点(PointCut) 连接点(JoinPoint)

在这里插入图片描述

这个咱们也不管,这里我们直接用一个狂神的例子吧,说实话他说的东西很简单,很好理解,Spring一天搞定基础其实问题不大。 那么这里也是有三种方式的,一个一个来吧。

SpringAPI接口实现

以下步骤

导入依赖

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

准备案例类

public interface UserService {

   public void add();

   public void delete();

   public void update();

   public void select();

}



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 select() {
       System.out.println("查询用户");
  }
}




public class Log implements MethodBeforeAdvice {
	
   //method : 要执行的目标对象的方法 前置增强 
   //objects : 被调用的方法的参数
   //Object : 目标对象
   @Override
   public void before(Method method, Object[] objects, Object o) throws Throwable {
       System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了");
  }
}



public class AfterLog implements AfterReturningAdvice {
   //returnValue 返回值  后置增强
   //method被调用的方法
   //args 被调用的方法的对象的参数
   //target 被调用的目标对象
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
       System.out.println("执行了" + target.getClass().getName()
       +"的"+method.getName()+"方法,"
       +"返回值:"+returnValue);
  }
}

进入配置文件

文件名字 bean1.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: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="nuc.ss.service.UserServiceImpl"/>
   <bean id="log" class="nuc.ss.log.Log"/>
   <bean id="afterLog" class="nuc.ss.log.AfterLog"/>

   <!--aop的配置-->
   <aop:config>
       <!--切入点 expression:表达式匹配要执行的方法-->
       <aop:pointcut id="pointcut" expression="execution(* nuc.ss.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 Test1 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        UserServer userService = (UserServer) context.getBean("userService");
        userService.select();
    }
}

自定义增强类

也就是咱们的那个Log不去实现那个接口 这个主要区别就是自己动手实现一个配置类+配置文件不一样,但是其他的都是一样用的。 接下来还是几个步骤

自定义类

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

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

修改配置文件

<bean id="diy" class="com.huterox.Log.DiyAOP"/>

<!--aop的配置-->
<aop:config>
    <!--自定义切面,ref要引用的类-->
    <aop:aspect ref="diy">
        <!--切入点-->
        <aop:pointcut id="point" expression="execution(* com.huterox.Server.UserServerIm.*(..))"/>
        <aop:before method="before" pointcut-ref="point"/>
        <aop:after method="after" pointcut-ref="point"/>
     
    </aop:aspect>
</aop:config>

测试 和前面的一样

@Test
public void test1() {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

    UserService userService = (UserService)context.getBean("userService");

    userService.add();
}

使用注解实现

我们拿到第二方法的例子。现在改一下

@Aspect
public class DiyAOP {
	@Before("execution(* com.huterox.Server.UserServerIm.*(..))")
    public void before() {
        System.out.println("方法执行前");
    }
	@Before("execution(* com.huterox.Server.UserServerIm.*(..))")
    public void after() {
        System.out.println("方法执行后");
    }
}

之后进入配置文件 一方面是注册一方面是进行注解支持的开启

<bean id="diy" class="com.huterox.Log.DiyAOP"/>

<!--aop开启注解支持-->
<aop:aspectj-autoproxy/>

之后就没有之后了,和前面一样使用。

环绕

那么目前已经介绍了before和after,基本够用了,但是这里还有一个什么环绕之类。 首先先看一个图: 在这里插入图片描述 这个我想应该很明白了吧! 那么咱们直接说怎么玩。

@Aspect
public class DiyAOP {
	@Before("execution(* com.huterox.Server.UserServerIm.*(..))")
    public void before() {
        System.out.println("方法执行前");
    }
	@Before("execution(* com.huterox.Server.UserServerIm.*(..))")
    public void after() {
        System.out.println("方法执行后");
    }
    @Around("execution(* com.huterox.Server.UserServerIm.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        //获取签名
        //Signature signature = jp.getSignature();
        //System.out.println("signature:" + signature);

        //执行方法
        Object proceed = jp.proceed();

        System.out.println("环绕后");
    }

}

总结

到目前为止Spring的基础部分就OK了,那么后面其实还有的是Spring和mybatis mvc之间的组合,那么我这边选择的是Spring Spring Boot mybatis-plus 所以目前到这里其实就可以了。总的来说内容不多,具体这么玩还得看看那个大头 Spring boot 。