2024.3.19@spring框架学习笔记

P101 GoF代理模式之JDK动态代理工具类封装
P101  start :
ProxyUtil类中的内容为:

package com.powernode.proxy.util;

import com.powernode.proxy.service.OrderService;
import com.powernode.proxy.service.TimerInvocationHandler;

import java.lang.reflect.Proxy;

public class ProxyUtil {

    /**
     * 封装一个工具方法,可以通过这个方法获取代理对象
     * @param target
     * @return
     */

    public static Object newProxyInstance(Object target){
            //底层是调用的还是JDK的动态代理。
       return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new TimerInvocationHandler(target));


    }
}

Client客户端类中的内容为:
package com.powernode.proxy.client;

import com.powernode.proxy.service.OrderService;
import com.powernode.proxy.service.OrderServiceImpl;
import com.powernode.proxy.service.TimerInvocationHandler;
import com.powernode.proxy.util.ProxyUtil;

import java.lang.reflect.Proxy;

public class Client {
    //客户端程序
    public static void main(String[] args) {

        //创建目标对象
        OrderService target = new OrderServiceImpl();
        //创建代理对象
        //三个参数:类加载器,代理类要实现的接口,调用处理器
        /*
        1.newProxyInstance 翻译为:新建代理对象
            也就是说,通过调用这个方法可以创建代理对象。
            本质上,这个Proxy.newProxyInstance()方法的执行,做了两件事:
                第一件事:再内存中动态的生成了一个代理类的字节码class。
                第二件事:new对象了。通过内存中生成的代理类这个代码,实例化了代理对象。
        2.关于newProxyInstance()方法的三个重要的参数,每一个什么含义,有什么用?
            第一个参数:ClassLoader loader
                类加载器。这个类加载器有什么用呢?
                    再内存当中生成的字节码也是class文件,要执行也得先加载到内存当中。
                    加载类就需要类加载器,所以这里需要指定类加载器。
                    并且JDK要求,目标类的类加载器必须和代理类的类加载器使用同一个。

            第二个参数:Class<?>[] interfaces
                代理类和目标类要实现同一个接口或同一些接口。
                在内存中生成代理类的时候,这个代理类是需要你告诉它实现哪些接口的。

            第三个参数:InvocationHandler h
                    InvocationHandler 被翻译为:调用处理器。是一个接口。
                    在调用处理器接口中编写的就是:增强代码。
                    因为具体要增强什么代码,JDK动态代理技术它是猜不到的。没有那么神。
                    既然是接口,就要写接口的实现类。

                    可能会有疑问?
                        自己还要动手写调用处理器接口的实现类,这不会类爆炸吗?不会。
                        因为这种调用处理器写一次就好。

                注意:代理对象和目标对象实现的接口一样,所以可以向下转型。
         */
//        OrderService proxyObj = (OrderService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
//                new TimerInvocationHandler(target));

        //上面代码通过一个工具类的封装,就简洁了。
        OrderService proxyObj = (OrderService) ProxyUtil.newProxyInstance(target);

        //调用代理对象的代理方法
        //注意:调用代理对象的代理方法的时候,如果你要做增强的话,目标对象的目标方法得保证执行。
        proxyObj.generate();
        proxyObj.modify();
        proxyObj.detail();
        String name = proxyObj.getName();
        System.out.println(name);
    }
}


P101  end
P102 GoF代理模式之CGLIB动态代理
CGLIB既可以代理接口,又可以代理类。底层采用继承的方式实现,所以被代理的目标不能使用final修饰,使用CGLIB需要引入它的依赖。
CGLIB依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

UserServicel类中的的内容:
package com.powernode.proxy.service;

public class UserService {
    //目标方法
    public boolean login(String username, String password){
        System.out.println("系统正在验证身份...");
        if ("admin".equals(username)&&"123".equals(password)) {
            return true;
        }

        return false;
    }
    //目标方法
    public void  logout(){
        System.out.println("系统正在退出...");
    }

}

TimerMethodInterceptor类中的内容:
package com.powernode.proxy.service;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class TimerMethodeInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object target, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //签名增强
        long begin = System.currentTimeMillis();
        //怎么调用目标对象的目标方法呢?
        Object retValue = methodProxy.invokeSuper(target, objects);
        //后面增强
        long end = System.currentTimeMillis();
        System.out.println("耗时" + (end - begin) + "毫秒");
        return retValue;
    }
}


Client类中的内容:
package com.powernode.proxy.client;

import com.powernode.proxy.service.TimerMethodeInterceptor;
import com.powernode.proxy.service.UserService;
import net.sf.cglib.proxy.Enhancer;

public class Client {
    public static void main(String[] args) {
        //创建字节码增强器对象
        //这个对象是CGLIB库当中的核心对象,就是依靠它来代理类。
        Enhancer enhancer = new Enhancer();


        //告诉CGLIB父类是谁。告诉CGLIB目标类是谁。
        enhancer.setSuperclass(UserService.class);

        //设置回调(等同于JDK动态代理当中的调用处理球,InvocationHandler)
        //在CGLIB当中不是InvocationHandler接口,是方法拦截器接口:MethodInterceptor
        enhancer.setCallback(new TimerMethodeInterceptor());

        //创建代理对象
        //这一步会做两件事:
        //第一件事:在内存中生成UserService类的子类,其实就是代理类的字节码。
        //第二件事:创建代理对象。
        //父类是UserService,子类这个代理类一定是UserService
        UserService userServiceProxy = (UserService) enhancer.create();

        //建议大家能够把CGLIB动态代理生成的代理对象的名字格式有点印象
        //根据这个名字可以推测框架底层是否使用了CGLIB动态代理
        System.out.println(userServiceProxy);


        //调用代理对象的代理方法。
        boolean success =  userServiceProxy.login("admin", "123");
        System.out.println(success ? "登录成功": "登录失败");

        userServiceProxy.logout();

    }
    //底层本质:
    //com.powernode.proxy.service.UserService$$EnhancerByCGLIB$$82cb55e3@5d3411d

}

运行结果:
耗时0毫秒
耗时15毫秒
com.powernode.proxy.service.UserService$$EnhancerByCGLIB$$82cb55e3@5d3411d
系统正在验证身份...
耗时2毫秒
登录成功
系统正在退出...
耗时0毫秒

P103 面向切面编程之面向切面编程的深入理解 start:

十五、面向切面编程AOP
IoC使软件组件松耦合。AOP让你能够捕捉系统中经常使用的功能,把它转化成组件。
AOP(Aspect Oriented Programming):面向切面编程,面向方面编程。(AOP是一种编程技术)
AOP是对OOP的补充延伸。
AOP底层使用的就是动态代理来实现的。
Spring的AOP使用的动态代理是:JDK动态代理 + CGLIB动态代理技术。Spring在这两种动态代理中灵活切换,如果是代理接口,会默认使用JDK动态代理,如果要代理某个类,这个类没有实现接口,就会切换使用CGLIB。当然,你也可以强制通过一些配置让Spring只使用CGLIB。
15.1 AOP介绍
一般一个系统当中都会有一些系统服务,例如:日志、事务管理、安全等。这些系统服务被称为:交叉业务
这些交叉业务几乎是通用的,不管你是做银行账户转账,还是删除用户数据。日志、事务管理、安全,这些都是需要做的。
如果在每一个业务处理过程当中,都掺杂这些交叉业务代码进去的话,存在两方面问题:
● 第一:交叉业务代码在多个业务流程中反复出现,显然这个交叉业务代码没有得到复用。并且修改这些交叉业务代码的话,需要修改多处。
● 第二:程序员无法专注核心业务代码的编写,在编写核心业务代码的同时还需要处理这些交叉业务。
使用AOP可以很轻松的解决以上问题。

用一句话总结AOP:将与核心业务无关的代码独立的抽取出来,形成一个独立的组件,然后以横向交叉的方式应用到业务流程当中的过程被称为AOP。
AOP的优点:
● 第一:代码复用性增强。
● 第二:代码易维护。
● 第三:使开发者更关注业务逻辑

P104  面向切面编程之七大术语  start:

● 连接点 Joinpoint
○ 在程序的整个执行流程中,可以织入切面的位置。方法的执行前后,异常抛出之后等位置。
● 切点 Pointcut
○ 在程序执行流程中,真正织入切面的方法。(一个切点对应多个连接点)
● 通知 Advice
○ 通知又叫增强,就是具体你要织入的代码。
○ 通知包括:
■ 前置通知
■ 后置通知
■ 环绕通知
■ 异常通知
■ 最终通知
● 切面 Aspect
○ 切点 + 通知就是切面。
● 织入 Weaving
○ 把通知应用到目标对象上的过程。
● 代理对象 Proxy
○ 一个目标对象被织入通知后产生的新对象。
● 目标对象 Target
○ 被织入通知的对象。

P105  面向切面编程之切点表达式  start:
15.3 切点表达式
切点表达式用来定义通知(Advice)往哪些方法上切入。
切入点表达式语法格式:
execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])
execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])

访问控制权限修饰符:
● 可选项。
● 没写,就是4个权限都包括。
● 写public就表示只包括公开的方法。
返回值类型:
● 必填项。
● * 表示返回值类型任意。
全限定类名:
● 可选项。
● 两个点“..”代表当前包以及子包下的所有类。
● 省略时表示所有的类。
方法名:
● 必填项。
● 表示所有方法。● set表示所有的set方法。
形式参数列表:
● 必填项
● () 表示没有参数的方法
● (..) 参数类型和个数随意的方法
● () 只有一个参数的方法● (, String) 第一个参数类型随意,第二个参数是String的。
异常:
● 可选项。
● 省略时表示任意异常类型。

P106  Spirng  AOP实现之概述 start:
Spring对AOP的实现包括以下3种方式:
● 第一种方式:Spring框架结合AspectJ框架实现的AOP,基于注解方式。
● 第二种方式:Spring框架结合AspectJ框架实现的AOP,基于XML方式。
● 第三种方式:Spring框架自己实现的AOP,基于XML配置方式。
实际开发中,都是Spring+AspectJ来实现AOP。所以我们重点学习第一种和第二种方式。
什么是AspectJ?(Eclipse组织的一个支持AOP的框架。AspectJ框架是独立于Spring框架之外的一个框架,Spring框架用了AspectJ)
AspectJ项目起源于帕洛阿尔托(Palo Alto)研究中心(缩写为PARC)。该中心由Xerox集团资助,Gregor Kiczales领导,从1997年开始致力于AspectJ的开发,1998年第一次发布给外部用户,2001年发布1.0 release。为了推动AspectJ技术和社团的发展,PARC在2003年3月正式将AspectJ项目移交给了Eclipse组织,因为AspectJ的发展和受关注程度大大超出了PARC的预期,他们已经无力继续维持它的发展。

15.4.1 准备工作
使用Spring+AspectJ的AOP需要引入的依赖如下:
<!--spring context依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.0-M2</version>
</dependency>
<!--spring aop依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>6.0.0-M2</version>
</dependency>
<!--spring aspects依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.0.0-M2</version>
</dependency>


Spring配置文件中添加context命名空间和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: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 http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>

107  AOP基于注解之准备工作  start:在上面!~
P108 Spring  AOP基于注解之实现步骤  start:
LogAspect类中的内容:
package com.powernode.spring6.service;

import jdk.swing.interop.SwingInterOpUtils;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component("logAspect")
@Aspect //切面类是需要使用@Aspect注解进行标注的。
public class LogAspect {  //切面

    //切面 = 通知 + 切点
    //通知就是增强,就是具体的要编写的增强代码
    //这里通知Advice以方法的形式出现。(因为方法中可以写代码)
    //@Before注解标注的方法就是一个前置通知。
    //括号中要写切点表达式
    //@Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表) 异常)")
    @Before("execution(* com.powernode.spring6.service.UserService.*(..) )")
    public void 增强(){
        System.out.println("我是一个通知,我是一段增强代码。。。。");
    }


}

UserService类中的内容:
package com.powernode.spring6.service;

import org.springframework.stereotype.Service;

@Service("userService")
public class UserService {//目标类

    public void login(){  //目标方法
        System.out.println("系统正在进行身份认证。。。。");
    }
}

spring配置文件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 http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--组件扫描 -->
    <context:component-scan base-package="com.powernode.spring6.service"/>

    <!--开启aspectj的自动代理 -->
    <!--spring容器在扫描类的时候,查看该类上是否有@Aspect注解,如果有,则给这个类生成代理对象. -->
    <!--
        proxy-target-class="true" 表示强制使用CGLIB代理
         proxy-target-class="false"  这是默认值,表示接口使用JDK动态代理,反之使用CGLIB代理。
      -->

    <aop:aspectj-autoproxy proxy-target-class="true"/>


</beans>
测试类中的内容:
package com.powernode.spring6.test;

import com.powernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAOPTest {

    @Test
    public void testBefore(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();
    }

}

运行结果:
我是一个通知,我是一段增强代码。。。。
系统正在进行身份认证。。。。
P109 Spring AOP基于注解之切面表达式 Start:
LogAspect类中的内容:
package com.powernode.spring6.service;

import jdk.swing.interop.SwingInterOpUtils;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component("logAspect")
@Aspect //切面类是需要使用@Aspect注解进行标注的。
public class LogAspect {  //切面

    //切面 = 通知 + 切点
    //通知就是增强,就是具体的要编写的增强代码
    //这里通知Advice以方法的形式出现。(因为方法中可以写代码)
    //@Before注解标注的方法就是一个前置通知。
    //括号中要写切点表达式
    //@Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表) 异常)")
    @Before("execution(* com.powernode.spring6.service..*(..) )")
    public void 增强(){
        System.out.println("我是一个通知,我是一段增强代码。。。。");
    }


}

OrderService类中的内容:
package com.powernode.spring6.service;

import org.springframework.stereotype.Service;

@Service("orderService")
public class OrderService {//目标类

    //目标方法
    public void generate(){
        System.out.println("生成订单");
    }

}

UserService类中的内容:
package com.powernode.spring6.service;

import org.springframework.stereotype.Service;

@Service("userService")
public class UserService {//目标类

    public void login(){  //目标方法
        System.out.println("系统正在进行身份认证。。。。");
    }

    public void logout(){
        System.out.println("退出系统。。。");
    }

}

spring类中的内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns: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 http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--组件扫描 -->
    <context:component-scan base-package="com.powernode.spring6.service"/>

    <!--开启aspectj的自动代理 -->
    <!--spring容器在扫描类的时候,查看该类上是否有@Aspect注解,如果有,则给这个类生成代理对象. -->
    <!--
        proxy-target-class="true" 表示强制使用CGLIB代理
         proxy-target-class="false"  这是默认值,表示接口使用JDK动态代理,反之使用CGLIB代理。
      -->

    <aop:aspectj-autoproxy proxy-target-class="true"/>


</beans>
测试类中的内容:
package com.powernode.spring6.test;

import com.powernode.spring6.service.OrderService;
import com.powernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAOPTest {

    @Test
    public void testBefore(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.login();
        userService.logout();


        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        orderService.generate();
    }

}

运行结果:
我是一个通知,我是一段增强代码。。。。
系统正在进行身份认证。。。。
我是一个通知,我是一段增强代码。。。。
退出系统。。。
我是一个通知,我是一段增强代码。。。。
生成订单

P110  Spring AOP基于注解之所有通知类型 start :

通知类型
通知类型包括:
● 前置通知:@Before 目标方法执行之前的通知
● 后置通知:@AfterReturning 目标方法执行之后的通知
● 环绕通知:@Around 目标方法之前添加通知,同时目标方法执行之后添加通知。
● 异常通知:@AfterThrowing 发生异常之后执行的通知
● 最终通知:@After 放在finally语句块中的通知

环绕的通知是最大的范围,在前置和后置的前面和后面
LogAspect类中的内容:
package com.powernode.spring6.service;

import jdk.swing.interop.SwingInterOpUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component("logAspect")
@Aspect //切面类是需要使用@Aspect注解进行标注的。
public class LogAspect {  //切面

    //切面 = 通知 + 切点
    //通知就是增强,就是具体的要编写的增强代码
    //这里通知Advice以方法的形式出现。(因为方法中可以写代码)
    //@Before注解标注的方法就是一个前置通知。
    //括号中要写切点表达式
    //@Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表) 异常)")
//    @Before("execution(* com.powernode.spring6.service..*(..) )")
//    public void 增强(){
//        System.out.println("我是一个通知,我是一段增强代码。。。。");
//    }

    //前置通知
    @Before("execution(* com.powernode.spring6.service..*(..) )")
    public void beforeAdvice(){
        System.out.println("前置通知");
    }

    //后置通知
    @AfterReturning("execution(* com.powernode.spring6.service..*(..) )")
    public void afterReturningAdvice(){
        System.out.println("后置通知");
    }
    //环绕通知(环绕是最大的通知,在前置通知之前,在后置通知之后。)
    @Around("execution(* com.powernode.spring6.service..*(..) )")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //前面的代码
        System.out.println("前环绕");
        //执行目标
        joinPoint.proceed();//执行目标
        //后面的代码
        System.out.println("后环绕");

    }

    //异常通知
    @AfterThrowing("execution(* com.powernode.spring6.service..*(..) )")
    public void afterThrowingAdvice(){
        System.out.println("异常通知");
    }

    //最终通知(finally语句块中的通知)
    @After("execution(* com.powernode.spring6.service..*(..) )")
    public void afterAdvice(){
        System.out.println("最终通知");

    }
}

OrderService类中的内容:
package com.powernode.spring6.service;

import org.springframework.stereotype.Service;

@Service("orderService")
public class OrderService {//目标类

    //目标方法
    public void generate(){
        System.out.println("系统正在生成订单。。。");
//        if (1 == 1) {
//                throw new RuntimeException("运行时异常。。。");
//            }
        }

    }

UserService类中的内容:
package com.powernode.spring6.service;

import org.springframework.stereotype.Service;

@Service("userService")
public class UserService {//目标类

    public void login(){  //目标方法
        System.out.println("系统正在进行身份认证。。。。");
    }

    public void logout(){
        System.out.println("退出系统。。。");
    }

}

spring配置文件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 http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--组件扫描 -->
    <context:component-scan base-package="com.powernode.spring6.service"/>

    <!--开启aspectj的自动代理 -->
    <!--spring容器在扫描类的时候,查看该类上是否有@Aspect注解,如果有,则给这个类生成代理对象. -->
    <!--
        proxy-target-class="true" 表示强制使用CGLIB代理
         proxy-target-class="false"  这是默认值,表示接口使用JDK动态代理,反之使用CGLIB代理。
      -->

    <aop:aspectj-autoproxy proxy-target-class="true"/>


</beans>
测试类中的内容:
package com.powernode.spring6.test;

import com.powernode.spring6.service.OrderService;
import com.powernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAOPTest {

    @Test
    public void testBefore(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//        UserService userService = applicationContext.getBean("userService", UserService.class);
//        userService.login();
//        userService.logout();


        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        orderService.generate();
    }

}

运行结果:
前环绕
前置通知
系统正在生成订单。。。
后置通知
最终通知
后环绕
P111  spring  AOP基于注解之切面顺序 start:
@Order()注解,括号里谁的数字最小,谁的优先级最高
LogAspect类中的内容:
package com.powernode.spring6.service;

import jdk.swing.interop.SwingInterOpUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component("logAspect")
@Aspect //切面类是需要使用@Aspect注解进行标注的。
@Order(2)
public class LogAspect {  //切面

    //切面 = 通知 + 切点
    //通知就是增强,就是具体的要编写的增强代码
    //这里通知Advice以方法的形式出现。(因为方法中可以写代码)
    //@Before注解标注的方法就是一个前置通知。
    //括号中要写切点表达式
    //@Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表) 异常)")
//    @Before("execution(* com.powernode.spring6.service..*(..) )")
//    public void 增强(){
//        System.out.println("我是一个通知,我是一段增强代码。。。。");
//    }

    //前置通知
    @Before("execution(* com.powernode.spring6.service..*(..) )")
    public void beforeAdvice(){
        System.out.println("前置通知");
    }

    //后置通知
    @AfterReturning("execution(* com.powernode.spring6.service..*(..) )")
    public void afterReturningAdvice(){
        System.out.println("后置通知");
    }
    //环绕通知(环绕是最大的通知,在前置通知之前,在后置通知之后。)
    @Around("execution(* com.powernode.spring6.service..*(..) )")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //前面的代码
        System.out.println("前环绕");
        //执行目标
        joinPoint.proceed();//执行目标
        //后面的代码
        System.out.println("后环绕");

    }

    //异常通知
    @AfterThrowing("execution(* com.powernode.spring6.service..*(..) )")
    public void afterThrowingAdvice(){
        System.out.println("异常通知");
    }

    //最终通知(finally语句块中的通知)
    @After("execution(* com.powernode.spring6.service..*(..) )")
    public void afterAdvice(){
        System.out.println("最终通知");

    }
}

OrderService类中的内容:
package com.powernode.spring6.service;

import org.springframework.stereotype.Service;

@Service("orderService")
public class OrderService {//目标类

    //目标方法
    public void generate(){
        System.out.println("系统正在生成订单。。。");
//        if (1 == 1) {
//                throw new RuntimeException("运行时异常。。。");
//            }
        }

    }

SecurityAspect类中的内容:
package com.powernode.spring6.service;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(3)
public class SecurityAspect {//安全切面

    //通知 + 切点
    @Before("execution(* com.powernode.spring6.service..*(..) )")
    public void beforeAdvice(){
        System.out.println("前置通知:安全。。。");
    }

}

UserService类中的内容:
package com.powernode.spring6.service;

import org.springframework.stereotype.Service;

@Service("userService")
public class UserService {//目标类

    public void login(){  //目标方法
        System.out.println("系统正在进行身份认证。。。。");
    }

    public void logout(){
        System.out.println("退出系统。。。");
    }

}

spring配置文件与上集相同
测试类中的内容:
package com.powernode.spring6.test;

import com.powernode.spring6.service.OrderService;
import com.powernode.spring6.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAOPTest {

    @Test
    public void testBefore(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
//        UserService userService = applicationContext.getBean("userService", UserService.class);
//        userService.login();
//        userService.logout();


        OrderService orderService = applicationContext.getBean("orderService", OrderService.class);
        orderService.generate();
    }

}

运行结果:
前环绕
前置通知
前置通知:安全。。。
系统正在生成订单。。。
后置通知
最终通知
后环绕
P112  spring AOP基于注解之通用切点 start:

LogAspect类中的内容:
package com.powernode.spring6.service;

import jdk.swing.interop.SwingInterOpUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component("logAspect")
@Aspect //切面类是需要使用@Aspect注解进行标注的。
@Order(2)
public class LogAspect {  //切面

    //切面 = 通知 + 切点
    //通知就是增强,就是具体的要编写的增强代码
    //这里通知Advice以方法的形式出现。(因为方法中可以写代码)
    //@Before注解标注的方法就是一个前置通知。
    //括号中要写切点表达式
    //@Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表) 异常)")
//    @Before("execution(* com.powernode.spring6.service..*(..) )")
//    public void 增强(){
//        System.out.println("我是一个通知,我是一段增强代码。。。。");
//    }


    //定义通用的切点表达式
    @Pointcut("execution(* com.powernode.spring6.service..*(..) )")
    public void 通用切点(){
        //这个方法只是一个标记,方法名随意,方法体中也不需要写任何代码
    }


    //前置通知
    @Before("通用切点()")
    public void beforeAdvice(){
        System.out.println("前置通知");
    }

    //后置通知
    @AfterReturning("通用切点()")
    public void afterReturningAdvice(){
        System.out.println("后置通知");
    }
    //环绕通知(环绕是最大的通知,在前置通知之前,在后置通知之后。)
    @Around("通用切点()")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //前面的代码
        System.out.println("前环绕");
        //执行目标
        joinPoint.proceed();//执行目标
        //后面的代码
        System.out.println("后环绕");

    }

    //异常通知
    @AfterThrowing("通用切点()")
    public void afterThrowingAdvice(){
        System.out.println("异常通知");
    }

    //最终通知(finally语句块中的通知)
    @After("通用切点()")
    public void afterAdvice(){
        System.out.println("最终通知");

    }
}

SecerityAspect类中的内容:
package com.powernode.spring6.service;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(3)
public class SecurityAspect {//安全切面

    //通知 + 切点
//    @Before("execution(* com.powernode.spring6.service..*(..) )")
    @Before("com.powernode.spring6.service.LogAspect.通用切点()")
    public void beforeAdvice(){
        System.out.println("前置通知:安全。。。");
    }

}

测试类与上集相同,spring配置文件与上集相同
运行结果:
前环绕
前置通知
前置通知:安全。。。
系统正在生成订单。。。
后置通知
最终通知
后环绕

P113 spring AOP基于注解之连接点  start:
LogAspect类中的内容:
package com.powernode.spring6.service;

import jdk.swing.interop.SwingInterOpUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component("logAspect")
@Aspect //切面类是需要使用@Aspect注解进行标注的。
@Order(2)
public class LogAspect {  //切面

    //切面 = 通知 + 切点
    //通知就是增强,就是具体的要编写的增强代码
    //这里通知Advice以方法的形式出现。(因为方法中可以写代码)
    //@Before注解标注的方法就是一个前置通知。
    //括号中要写切点表达式
    //@Before("execution(修饰符 返回值类型 全限定类名 方法名(形式参数列表) 异常)")
//    @Before("execution(* com.powernode.spring6.service..*(..) )")
//    public void 增强(){
//        System.out.println("我是一个通知,我是一段增强代码。。。。");
//    }


    //定义通用的切点表达式
    @Pointcut("execution(* com.powernode.spring6.service..*(..) )")
    public void 通用切点(){
        //这个方法只是一个标记,方法名随意,方法体中也不需要写任何代码
    }


    //前置通知
    @Before("通用切点()")
    public void beforeAdvice(JoinPoint joinPoint){
        System.out.println("前置通知");
        //这个JoinPoint joinPoint,在spring容器调用这个方法的时候自动传过来
        //我们可以直接用,用这个JoinPoint joinPoint 干啥?
//        Signature signature = joinPoint.getSignature(); //获取目标方法的签名
        //Signature signature = joinPoint.getSignature();
        //通过方法的前面可以获取到一个方法的具体信息。
        //获取目标方法的方法名
        System.out.println("目标方法的方法名"+joinPoint.getSignature().getName());
    }

    //后置通知
    @AfterReturning("通用切点()")
    public void afterReturningAdvice(){
        System.out.println("后置通知");
    }
    //环绕通知(环绕是最大的通知,在前置通知之前,在后置通知之后。)
    @Around("通用切点()")
    public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //前面的代码
        System.out.println("前环绕");
        //执行目标
        joinPoint.proceed();//执行目标
        //后面的代码
        System.out.println("后环绕");

    }

    //异常通知
    @AfterThrowing("通用切点()")
    public void afterThrowingAdvice(){
        System.out.println("异常通知");
    }

    //最终通知(finally语句块中的通知)
    @After("通用切点()")
    public void afterAdvice(){
        System.out.println("最终通知");

    }
}

其他文件与上集相同
运行结果:
前环绕
前置通知
目标方法的方法名generate
前置通知:安全。。。
系统正在生成订单。。。
后置通知
最终通知
后环绕

P114 spring AOP基于注解之全注解开发 start :
Time:4h
视频网址:
https://www.bilibili.com/video/BV1Ft4y1g7Fb?p=113&vd_source=ff898217e3612fcbdefecfdc49657ab1

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值