脚踏Spring----超详细讲解

Spring两大核心
!IOC:工厂模式
!AOP:代理模式
IOC
IOC是spring框架的灵魂,控制反转。
传统开发:

Student student = new Student();

IOC容器举例:
传统方式就是比如你去超市买东西,你得去拿袋子自己要啥买啥。
当你有了IOC容器就好像你有了一个保姆,你要啥他会帮你拿,而你就省略了拿东西这一步。你自己拿现成的结果就是了。

lombok可以帮助开发者自动生生成实体类相关的方法,在IDEA中使用,必须先安装插件。
在这里插入图片描述

开发步骤:
1.创建Maven工程,在pom.xml导入相关依赖

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

2.在resources路径下创建spring.xml。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 创建User    -->
   <bean id="student" class="com.wdzl.pojo.Student"></bean>
</beans>

3.IOC容器通过读取spring.xml配置文件,加载bean标签来创建对象。
4.调用API获取IOC容器已经创建的对象

public class Test {
    public static void main(String[] args) {
        //传统的开发方式,手动创建对象
//        Student student = new Student();
//        System.out.println(student);
        //IOC容器自动创建对象,开发者只需要取出对象即可。
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //方式1:
        //Student student =(Student) applicationContext.getBean("student");
        //方式2:
        Student student =(Student) applicationContext.getBean(Student.class);
        System.out.println(student);
    }
}

IOC容器创建bean的两种方式
1.通过无参构造函数

 <bean id="student" class="com.wdzl.pojo.Student"></bean>

给成员变量赋值:

   <bean id="student" class="com.wdzl.pojo.Student">
       <property name="id" value="1"></property>
       <property name="name" value="唐某人"></property>
       <property name="age" value="18"></property>
   </bean>

其实是通过setId,setName,setAge,方法得到的;反射模式。
2.通过有参构造函数

    <bean id="student5" class="com.wdzl.pojo.Student">
        <constructor-arg index="0" value="7"></constructor-arg>
        <constructor-arg index="1" value="赵童"></constructor-arg>
        <constructor-arg index="2" value="25"></constructor-arg>
    </bean>
    <bean id="student4" class="com.wdzl.pojo.Student">
        <constructor-arg name="id" value="4"></constructor-arg>
        <constructor-arg name="name" value="去波"></constructor-arg>
        <constructor-arg name="age" value="12"></constructor-arg>

    </bean>

从IOC容器中取bean
1.通过id取值

        //方式1:
        //Student student =(Student) applicationContext.getBean("student");

2.通过类型取值

        //方式2:
        Student student =(Student) applicationContext.getBean(Student.class);

当IOC容器中同时存在两个或两个以上的Student Bean时,就会抛出异常,因为没有唯一的bean。
在这里插入图片描述
bean的属性中如果包括特殊字符,如下处理即可

    <bean id="classes" class="com.wdzl.pojo.Classes">
        <property name="id" value="1"></property>
        <property name="name">
            <value><![CDATA[<一班>]]></value>
        </property>
    </bean>

IOC DI
DI 指的是bean之间的依赖注入,设置对象之间的级联关系。
Classes

@Data
public class Classes {
    private Integer id;
    private String name;

}

Student

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Classes classes;
    public Student(Integer id,String name,Integer age){
        System.out.println("通过有参构造创建对象");
        this.id=id;
        this.name=name;
        this.age=age;
    }
    public Student(Integer id,String name){
        System.out.println("通过有参构造创建对象");
        this.id=id;
        this.name=name;
    }
}

spring-di.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">
<!--    Classes-->
    <bean id="classes" class="com.wdzl.pojo.Classes">
        <property name="id" value="1"></property>
        <property name="name" value="一班"></property>
    </bean>
<!--  Student  -->
    <bean id="student" class="com.wdzl.pojo.Student">
        <property name="id" value="100"></property>
        <property name="name" value="唐某"></property>
        <property name="age" value="18"></property>
        <property name="classes" ref="classes"></property>
    </bean>
</beans>

Test2 测试类

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext applicationContext  = new ClassPathXmlApplicationContext("spring-di.xml");
//        String[] names = applicationContext.getBeanDefinitionNames();//获取bean所有id
//        for (String name:names) {
//            System.out.println(name);
//        }
        Classes classes = (Classes) applicationContext.getBean("classes");
        Student student = (Student) applicationContext.getBean("student");
        System.out.println(classes);
        System.out.println(student);
    }
}

bean 之间的级联需要使用 ref 属性完成映射,而不能直接使用value,否则会抛出类型转换异常。
在这里插入图片描述
Classes

@Data
public class Classes {
    private Integer id;
    private String name;
    private List<Student> studentList;
}

spring-di.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">
<!--    Classes-->
    <bean id="classes" class="com.wdzl.pojo.Classes">
        <property name="id" value="1"></property>
        <property name="name" value="一班"></property>
        <property name="studentList">
            <list>
                <ref bean="student"></ref>
                <ref bean="student2"></ref>
            </list>
        </property>
    </bean>
<!--  Student  -->
    <bean id="student" class="com.wdzl.pojo.Student">
        <property name="id" value="100"></property>
        <property name="name" value="唐某"></property>
        <property name="age" value="18"></property>
    </bean>
    <bean id="student2" class="com.wdzl.pojo.Student">
        <property name="id" value="200"></property>
        <property name="name" value="曲mou"></property>
        <property name="age" value="22"></property>

    </bean>
</beans>

Spring 中的bean
bean是根据scope来生成的,表示bean的作用域,scope中有四种类型:
! singleton,单例,表示通过spring容器获取的对象是唯一的,默认值。
!prototype,原型,表示通过spring容器获取的对象是不同的。
!request,请求,表示在一次HTTP请求内有效。
!session,会话,表示在一个用户内有效。
request,session 适用于Web项目。

singleton 模式下,只要加载IOC容器,无论是否从IOC中取出bean,配置文件中的bean都会被创建,而去无论你取1次或者1万次,都只会创建对象。

prototype 模式下,如果不从IOC中取bean,则不创建对象,取一次bean,就会创建一个对象。

spring的继承
spring继承不同于Java中的继承,区别:Java中的继承是针对于类的,而spring的继承是针对对象(bean)的。
spring的继承中,子bean可以继承父bean中所有成员变量的值。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user1" class="com.wdzl.pojo.User" >
        <property name="id" value="1"></property>
        <property name="name" value="关羽"></property>
    </bean>

    <bean id="user2" class="com.wdzl.pojo.User" parent="user1">
        <property name="name" value="李四"></property>
    </bean>
</beans>

通过bean标签的parent属性建立继承关系,同时子bean可以覆盖父bean的属性值。
spring的继承是针对对象的,所以子bean和父bean并不需要属于同一个数据类型,只要其成员变量,列表一致即可。

Spring的依赖
用来设置两个bean的创建顺序。
IOC 容器默认情况下是通过spring.xml中bean的配置顺序来决定创建顺序的,配置在前面的bean会先创建。
在不更改 spring.xml配置顺序的前提下,通过设置bean之间的依赖关系来调整bean的创建顺序。

    <!-- 创建User    -->
    <bean id="account" class="com.wdzl.pojo.Account" depends-on="user"></bean>
    <bean id="user" class="com.wdzl.pojo.User"></bean>

上述代码结构是先创建user在创建account。

spring 读取外部资源
实际开发中,数据库的配置一般会单独保存到后缀为properties的文件中,方便维护的修改,如果使用spring来加载数据源,就需要在spring.xml中读取properties中的数据,这就是读取外部资源。
jdbc.properties

user = root
password = 123456
url = jdbc:mysql://location:3306/mybatis
driverName = com.mysql.jdbc.Driver

spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--  导入外部资源-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--    SpEL-->
    <bean id="dataSource" class="com.wdzl.pojo.DataSource">
        <property name="password" value="${password}"></property>
        <property name="user" value="${user}"></property>
        <property name="url" value="${url}"></property>
        <property name="driverName" value="${driverName}"></property>
    </bean>

</beans>

Srping p 命名空间

P 命名空间可以用来简化bean的配置。

    <bean id="student" class="com.wdzl.pojo.Student" p:id="1" p:age="18" p:name="唐某人" p:classes-ref="classes">

    </bean>
    <bean id="classes" class="com.wdzl.pojo.Classes" p:name="测控1802" p:id="2"></bean>

Spring 工厂方法
IOC 通过工厂模式创建bean有两种方式:
! 静态工厂方法
! 实例工厂方法
区别在于:静态工厂类不需要实例化,而实例工厂类需要实例化

静态工厂方法
1.创建Car类

@Data
@AllArgsConstructor
public class Car {
    private Integer num;
    private String brand;
}

2.创建静态工厂类,静态工厂方法

public class StaticCarFactory {
    private static Map<Integer, Car> carMap;
    static {
        carMap = new HashMap<>();
        carMap.put(1,new Car(1,"奥迪"));
        carMap.put(2,new Car(2,"宝马"));
    }
    public static Car getCar(Integer num){
        return carMap.get(num);
    }

}

3.spring.xml

    <bean id="car1" class="com.wdzl.factory.StaticCarFactory" factory-method="getCar">
        <constructor-arg value="1"></constructor-arg>
    </bean>
</beans>

factory-method 指向静态方法
constructor-arg 的value属性是调用静态方法传入的参数

实例工厂方法
1.创建实例工厂类,工厂方法

public class InstanceCarFactory {
    private Map<Integer, Car> carMap;
    public InstanceCarFactory (){
        carMap = new HashMap<>();
        carMap.put(1,new Car(1,"奥迪"));
        carMap.put(2,new Car(2,"宝马"));
    }
    public Car getCar(Integer num){
        return carMap.get(num);
    }
}

2.spring.xml

<!--    实例工厂类-->
    <bean id="instanceCarFactory" class="com.wdzl.factory.InstanceCarFactory"></bean>

<!--    通过实例工厂获取Car-->
    <bean id="car2" factory-bean="instanceCarFactory" factory-method="getCar">
        <constructor-arg value="2"></constructor-arg>
    </bean>

区别:
静态工厂方法创建Car对象,不需要实例化工厂对象,因为静态工厂的静态方法,不需要创建对象即可调用,
spring.xml中只配置一个bean,即最终结构Car即可。

实例化工厂方法创建Car对象,需要实例化工厂对象,因为getCar方法是非静态的,就必须通过实例化对象才能调用,所有就必须要创建工厂对象,spring.xml中需要配置两个bean,一个是工厂bean,一个是Car bean。

spring.xml中 class + factory-method的形式是直接调用类中的工厂方法
spring.xml中 factory-bean+factory-method 的形式则是调用工厂bean中的工厂方法,就必须先创建工厂bean

spring IOC 自动装载 autowire
自动装载是spring提供的一种更加简便的方式来完成DI,不需要手动配置property,IOC容器会自动选择bean完成注入。
自动装载有两种方式:
!byName,通过属性名完成自动装载
!byType,通过对应的数据类型完成自动装载。

byName操作如下:
1.创建Person实体类:

@Data
public class Person {
    private Integer id;
    private String name;
    private Car car;
}

2.在spring.xml中配置Car和Person对应的bean,并且通过自动装载完成依赖注入。

    <bean id="person" class="com.wdzl.pojo.Person" autowire="byName">
        <property name="name" value="唐某人"></property>
        <property name="id" value="1"></property>
    </bean>

    <bean id="car" class="com.wdzl.pojo.Car">
        <constructor-arg name="num" value="1"></constructor-arg>
        <constructor-arg name="brand" value="大众"></constructor-arg>
    </bean>

byTypr操作如下:

    <bean id="person" class="com.wdzl.pojo.Person" autowire="byType">
        <property name="name" value="唐某人"></property>
        <property name="id" value="1"></property>
    </bean>

    <bean id="car1" class="com.wdzl.pojo.Car">
        <constructor-arg name="num" value="1"></constructor-arg>
        <constructor-arg name="brand" value="大众"></constructor-arg>
    </bean>

使用byType 进行自动装载时,必须保证IOC中只有一个符合条件的bean,否则会报出异常信息
在这里插入图片描述
spring IOC基于注解的开发
spring IOC 的作用是帮助开发者创建项目中所需要的bean,同时完成bean之间的依赖注入关系,DI。
实现该功能有两种方式:
!基于XML配置。
!基于注解。
基于注解有两步操作,缺一不可:
1.配置自动扫包

<!--    配置自动扫包-->
    <context:component-scan base-package="com.wdzl.pojo"></context:component-scan>

2.添加注解


@Data
@Component
public class Repository {
    private DataSource dataSource;
}

DI

@Data
@Component
public class DataSource {
    private String user;
    private String password;
    private String url;
    private String driverName;
}
@Data
@Component
public class Repository {
    @Autowired
    private DataSource dataSource;
}

@Autowires 默认是通过byType来进行注入的,如果要改为byName,需要配合@Qualifier注解来完成。

    @Autowired
    //@Qualifier(value = "ds")
    private DataSource dataSource;

表示将IOC中id为ds的bean注入到repository中。
实体类中普遍的成员变量(String , 包装类等)可以通过@Value注解进行赋值。

@Data
@Component
public class DataSource {
    @Value("root")
    private String user;
    @Value("123456")
    private String password;
    @Value("jdbc:mysql://location:3306/mybatis")
    private String url;
    @Value("com.mysql.jdbc.Driver")
    private String driverName;
}

等同于spring.xml中

    <bean id="ds" class="com.wdzl.pojo.DataSource">
        <property name="user" value="root"></property>
        <property name="password" value="123456"></property>
        <property name="url" value="jdbc:mysql://location:3306/mybatis"></property>
        <property name="driverName" value="com.mysql.jdbc.Driver"></property>
    </bean>

实际开发的使用:
实际开发中我们会将程序分为三层:
!Controller
! Service
! DAO(Repository)
关系:Controller----》Service ----》DAO

在这里插入图片描述
@Component 注解是将注解的类加载到IOC容器当中,实际开发中可以根据业务需求分别使用@Controller,@Service,@Repository注解来控制层类,业务层类,持久层类。

MyController

@Setter
@Component
public class MyController {
@Autowired
    private MyService myService;
    /**
     * 模拟客户端
     */
    public String  service(Double score){
        return myService.doService(score);
    }
}

MyService 接口


public interface MyService {
    public String doService(Double score);
}

MyService实现类

@Component
@Setter
public class MyServiceImpl implements MyService {
    @Autowired
    private MyRepository myRepository;
    @Override
    public String doService(Double score) {
        return myRepository.doRepository(score);
    }
}

MyRepository 接口

@Component
public interface MyRepository {
    public String doRepository(Double score);
}

MyRepository 实现类

@Component
public class MyRepository implements com.wdzl.repository.MyRepository {
    @Override
    public String doRepository(Double score) {
        String result="";
        if (score < 60){
            result = "不及格";
        }
        if (score>= 60 && score < 80){
            result = "及格";
        }
        if (score >= 80){
            result = "优秀";
        }
        return result;
    }
}

基于XML方式:

        <bean id="controller" class="com.wdzl.controller.MyController">
            <property name="myService" ref="service"></property>
        </bean>

        <bean id="service" class="com.wdzl.service.impl.MyServiceImpl">
            <property name="myRepository" ref="repository"></property>
        </bean>

        <bean id="repository" class="com.wdzl.repository.impl.MyRepository"></bean>

基于注解方式已在上面的代码了 自己看去 嘿嘿嘿

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

注意:注解和自动装配不能写在接口上。

Spring IOC 的底层实现
核心技术点:XML 解析 + 反射
具体的思路:
1.根据需求编写XML文件,配置需要的bean。
2.编写程序读取XML文件,获取bean相关信息,类,属性,id。
3.根据第二部获取到的信息,结合反射机制动态创建对象,同时完成属性的赋值。
4.将创建好的bean存入到Map集合,设置key-value映射,key就是bean中的id值,value就是bean对象。
5.提供方法从Map中通过id中通过id获取到对应的value。

Spring AOP
AOP (Aspect Oriented Programming) 面向切面编程。
OOP (Object Oriented Programming)面向对象编程,用对象化的思想完成编程。
AOP 是对OOP 的一个补充,是在另外一个维度上抽出对象。
具体是指程序运行时动态的将非业务代码切入到业务代码中,从而实现程序的解耦合,将非业务代码抽象抽象成一个对象,对对象编程就是面向切面编程。
在这里插入图片描述
上述形式的代码维护性差,没有代码复用性,使用AOP进行优化,如下图所示:

在这里插入图片描述
AOP 优点:
!可以降低模块之间的复用性。
!可以提高代码的复用性
!提高代码的维护性
!集中管理非业务代码,便于管理
!业务代码不受非业务代码的影响,逻辑更加清晰。
通过一个例子来了解AOP:
1.创建一个计算器的接口Cal。

public interface Cal {
    public int add(int num1,int num2);
    public int sub(int num1,int num2);
    public int mul(int num1,int num2);
    public int div(int num1,int num2);
}

2.创建接口的实现类:

public class CalImpl implements Cal {
    @Override
    public int add(int num1, int num2) {
        int result= num1 + num2;
        return result;
    }

    @Override
    public int sub(int num1, int num2) {
        int result = num1-num2;
        return result;
    }

    @Override
    public int mul(int num1, int num2) {
        int result = num1 * num2;
        return result;
    }

    @Override
    public int div(int num1, int num2) {
        int result = num1 / num2;
        return result;
    }
}

日志打印
!在每个方法开始位置输出参数信息。
!在每个方法方法结束位置输出结果信息。

对于计算机来讲,加减乘除就是业务代码,日志打印就是非业务代码。
AOP 如何实现?我们需要使用动态代理的方式来实现。
代理首先应该具备CalImpl的所有功能,并在此基础上,扩展出打印日志的功能。
1.删除Callmpl方法中所有打印日志的代码,只保留业务代码。
2.创建MyInvocationHandler类,实现InvocationHandler接口,生成动态代理类。
动态代理类,需要动态生成,需要获取到委托类的接口信息,根据这些接口信息动态生成一个代理类,然后ClassLoader用来将动态生成的类加载到JVM中。

public class MyInvocationHandler implements InvocationHandler {
    //委托对象
    private Object object = null;

    //返回代理对象
    public Object bind(Object object){
        this.object=object;
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //实现业务代码和非业务代码的解耦合
        System.out.println(method.getName() +"方法参数是"+ Arrays.toString(args));
        Object result = method.invoke(this.object, args);
        System.out.println(method.getName()+"计算结果是" +result);
        return result;
    }
}


public class Test {
    public static void main(String[] args) {
        //实例化委托对象
        Cal cal = new CalImpl();
        //获取代理对象
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        Cal proxy = (Cal) myInvocationHandler.bind(cal);
        proxy.add(10,2);
        proxy.sub(10,2);
        proxy.mul(5,3);
        proxy.div(10,2);
    }
}

上述代码通过动态代理机制实现了业务代码和非业务代码的解耦合,这是spring AOP的底层实现机制,真正在使用spring AOP 进行开发时,不需要这么复杂,可以用更好的解决方式进行开发。
spring AOP 开发步骤
在这里插入图片描述

1.创建切面类

@Component
@Aspect
public class LoggerAspect {
    @Before("execution(public int com.wdzl.aop.impl.CalImpl.add(..))")
    public void before(JoinPoint joinPoint){
        String name = joinPoint.getSignature().getName();
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println(name + "方法的参数是"+args);
    }
}

2.委托类也需要添加@Compoent
!@Component,将切面编程加载到IOC容器当中。
!@Aspect 表示该类是一个切面类。
!@Before,表示方法的执行时机实在业务代码之前,execution表达式表示切入点是Callmpl类中的add方法。
!@After表示方法的执行时机实在业务代码之后,execution表达式表示切入点是Callmpl类中的add方法。
!@AfterReturning,表示方法的执行时机是在业务返回结果之后,execution表达式表示切入点是Callmpl类中的add方法,returning是将业务方法的返回值与切面类方法的形参进行绑定。
!@afterThrowing,表示方法执行时机是在业务方法抛出异常之后,excution表达式表示切入点是Callmpl类中的add方法,throwing是将业务方法的异常与切面类方法的形参进行绑定。


@Component
public class CalImpl implements Cal {
    @Override
    public int add(int num1, int num2) {

        int result= num1 + num2;

        return result;
    }

    @Override
    public int sub(int num1, int num2) {

        int result = num1-num2;

        return result;
    }

    @Override
    public int mul(int num1, int num2) {

        int result = num1 * num2;

        return result;
    }

    @Override
    public int div(int num1, int num2) {

        int result = num1 / num2;

        return result;
    }
}

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       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/context
        http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--自动扫包-->
    <context:component-scan base-package="com.wdzl.aop"></context:component-scan>

    <!--为委托对象自动生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>


</beans>

aop:aspectj-autoproxy,spring IOC容器会结合切面对象和委托对象自动生成动态代理对象,AOP底层就是通过动态代理机制完成的。
AOP 的概念:
!面向对象:根据切面抽象出来的对象, Callmpl所有方法中需要加入日志的部分,抽象成一个切面类LoggerAspect。
!通知:切面对象具体执行的业务,即非业务代码,LoggerAspect对象打印日志代码。
!目标:被横切的对象,即Callmpl,将通知加入其中。
!代理:切面对象,通知,目标混合之后的结果,即我们使用JDK动态代理机制创建的对象。
!连接点:需要被横切的位置,即通知要插入业务代码具体位置。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值