• Spring AOP实现 | 代理模式分析


    在这里插入图片描述

    💗wei_shuo的个人主页

    💫wei_shuo的学习社区

    🌐Hello World !


    Sping AOP

    Spring AOP:控制反转

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

    在这里插入图片描述

    代理模式

    • 代理模式是程序设计中的一种设计模式
    • 所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源

    代理模式分类:

    • 静态代理
    • 动态代理

    优势:

    • 真实角色更加纯粹,不用关注公共业务
    • 公共业务交给代理角色,实现业务分工
    • 公共业务发生扩展时,方便集中管理

    劣势:

    • 一个真实角色会产生一个代理,代码量会翻倍、效率降低

    静态代理

    角色分析:

    • 抽象角色:一般会使用接口或者抽象类来解决
    • 真实代理:被代理的角色
    • 代理角色:代理真实角色
    • 客户:访问代理对象者
    • 接口
    public interface Rent {
        public void rent();
    }
    
    • 1
    • 2
    • 3
    • 真实角色
    public class Host {
        public void rent(){
            System.out.println("房东房子出租");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 代理角色
    public class Proxy implements Rent{
        private Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        public void rent(){
            host.rent();
        }
    
        //看房
        public void seeHouse(){
            System.out.println("中介带你看房");
        }
    
        //收中介费
        public void money(){
            System.out.println("收中介费");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 客户端访问代理角色
    public class Client {
        public static void main(String[] args) {
            //创建房东对象
            Host host = new Host();
            //代理
            Proxy proxy = new Proxy(host);  //通过代理调用房东对象
            proxy.rent();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    动态代理

    动态代理:

    • 动态代理和静态代理角色一样
    • 动态代理的代理类是动态生成
    • 动态代理是一个接口,对应一类业务
    • 动态代理可以代理多个类,只要实现一个接口

    动态代理分类:

    • 基于接口——JDK动态代理
    • 基于类——cglib
    • Java字节码——Javasist

    两种类了解:

    • Proxy——代理
    • InvocationHandl——调用处理程序

    Proxy类:生成动态代理实例

    • Proxy创建动态代理类的实例提供了静态方法,也是所有动态代理类的父类的方法创建

    方法:

    //返回指定的代理实例的调用处理程序
    getInvocationHandler(Object proxy) 
    
    //返回 java.lang.Class对象的代理类,给出了类装载器和一个阵列的接口
    getProxyClass(ClassLoader loader,<?>... interfaces) 
    
    //如果指定的类是动态生成的可利用 getProxyClass法或代理类 newProxyInstance方法返回true
    isProxyClass(<?> cl) 
    
    //返回指定的接口,将方法调用指定的调用处理程序的代理类的一个实例。 
    newProxyInstance(ClassLoader loader,<?>[] interfaces, InvocationHandler h) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    InvocationHandl类:调用处理程序并返回结果

    • InvocationHandler是通过一个代理实例调用处理程序实现的接口。
    • 每个代理实例都有一个相关的调用处理程序。当一个方法是在一个代理实例调用,调用的方法进行编码并派遣其调用处理程序的invoke方法

    方法:

    //在代理实例上处理方法调用,并返回结果
    invoke(Object proxy, 方法 method, Object[] args) 
    
    • 1
    • 2
    • proxy — 调用该方法的代理实例
    • method — 反射获取到的接口的方法
    • args — 使用此方法时传入的参数数组
    • ProxyInvocationHandler动态代理类
    public class ProxyInvocationHandl implements InvocationHandler {
    
        //被代理的接口
        private Object target;
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
    
        //生成得到代理类
        public Object getProxy() {
            //this.getClass().getClassLoader()  加载类所在位置
            //rent.getClass().getInterfaces()   表示代理接口
            //this	==	InvocationHandler实现类
            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 + "方法");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • Client客户类
    public class Client {
        public static void main(String[] args) {
            //真实角色:被代理的角色
            UserServiceImp userService = new UserServiceImp();
            //代理角色:代理真实角色
            ProxyInvocationHandl pih = new ProxyInvocationHandl();
    
            //设置代理对象
            pih.setTarget(userService);
            //动态生成代理类
            UserService proxy = (UserService) pih.getProxy();
    
            proxy.query();
        }
    }
    
    /*
    执行了query方法
    [Debug]使用了query方法
    查询用户
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    AOP概述

    提供声明式事物,允许用户自定义切面

    • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是很切关注点,如:日志,安全,缓存,事物……
    • 切面(ASPECT):横切关注点被模块化的特殊对象。
    • 通知(Advice):切面必须要完成的工作。
    • 目标(Target):被通知对象。
    • 代理(Proxy):向目标对象应用通知之后创建的对象。
    • 切入点(PointCut):切面通知执行的"地点"的定义。
    • 连接点(JoinPoint):与切入点匹配的执行点。

    Spring实现AOP

    方式一:使用Spring的API接口实现AOP

    • 使用AOP织入,需要导入一个依赖包
        <dependencies>
            <dependency>
                <groupId>org.aspectjgroupId>
                <artifactId>aspectjweaverartifactId>
                <version>1.9.4version>
            dependency>
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • applicationContext.xml
    
    <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
            ">
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 前置Log日志类
    public class log implements MethodBeforeAdvice {
    
        //method:要执行的目标对象方法
        //object:参数
        //target:目标对象
        @Override
        public void before(Method method, Object[] objects, Object target) throws Throwable {
            System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 后置AfterLog类
    public class AfterLog implements AfterReturningAdvice {
    
        //returnValue:返回值
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
            System.out.println("执行了"+method.getName()+"放回结果为:"+returnValue);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • UserService接口
    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void select();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • UserServiceImpl接口实现类
    public class UserServiceImpl implements UserService{
        public void add() {
            System.out.println("增加了一个用户");
        }
    
        public void delete() {
            System.out.println("删除了一个用户");
        }
    
        public void update() {
            System.out.println("更新了一个用户");
        }
    
        public void select() {
            System.out.println("查询了一个用户");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 将UserServiceImpl接口实现类注册到Spring中,即applicationContext.xml中
    
    <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 id="userService" class="com.wei.service.UserServiceImpl"/>
    
        <bean id="log" class="com.wei.log.log"/>
    
        <bean id="agter" class="com.wei.log.AfterLog"/>
    
    
    
    
        
        <aop:config>
            
            <aop:pointcut id="pointcut" expression="execution(* com.wei.service.UserServiceImpl.*(..))"/>
    
            
            <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
            <aop:advisor advice-ref="agter" pointcut-ref="pointcut"/>
        aop:config>
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • MyTest测试类
    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            //动态代理的是接口
            UserService userService = (UserService) context.getBean("userService");
            userService.delete();
    
        }
    }
    
    /*
    执行结果:
    com.wei.service.UserServiceImpl的delete被执行了
    删除了一个用户
    执行了delete放回结果为:null
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    方式二:自定义实现AOP

    • 自定义Diy类
    public class DiyPointCut {
        public void before(){
            System.out.println("===========方法执行前===========");
        }
    
        public void after(){
            System.out.println("===========方法执行后===========");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 将Diy类注册到Spring中,即applicationContext.xml中
    
    <bean id="diy" class="com.wei.diy.DiyPointCut"/>
    
    <aop:config>
        
        <aop:aspect ref="diy">
            
            
            <aop:pointcut id="point" expression="execution(* com.wei.service.UserServiceImpl.*(..))"/>
    
            
            
            <aop:before method="before" pointcut-ref="point"/>
            <aop:after method="after" pointcut-ref="point"/>
        aop:aspect>
    aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • MyTest测试类
    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            //动态代理的是接口
            UserService userService = (UserService) context.getBean("userService");
            userService.delete();
    
        }
    }
    
    /*
    ===========方法执行前===========
    删除了一个用户
    ===========方法执行后===========
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    aop中execution 表达式(*execution(\* 包名.\*.*(..))*)
    
    • 1
    • 整个表达式可以分为五个部分:

      • execution(): 表达式主体
      • 第一个*号:方法返回类型, *号表示所有的类型
      • 包名:表示需要拦截的包名
      • 第二个*号:表示类名,*号表示所有的类
      • *(…):最后这个星号表示方法名,*号表示所有的方法,后面( )里面表示方法的参数,两个句点表示任何参数
        
        
        <aop:pointcut id="point" expression="execution(* com.wei.service.UserServiceImpl.*(..))"/>
    
    • 1
    • 2
    • 3

    方式三:使用注解实现AOP

    • 创建AnnotationPointCut类
    //方式三:使用注解实现AOP
    //  @Aspect 标注这个类是一个切面
    @Aspect
    public class AnnotationPointCut {
    
        //后置增强
        @Before("execution(* com.wei.service.UserServiceImpl.*(..))")
        public void before() {
            System.out.println("======方法执行前======");
        }
    
        //前置增强
        @After("execution(* com.wei.service.UserServiceImpl.*(..))")
        public void after() {
            System.out.println("======方法执行后======");
        }
    
        //在环绕增强中,可以给一个参数,代表要获取处理切入的点
        @Around("execution(* com.wei.service.UserServiceImpl.*(..))")
        public void around(ProceedingJoinPoint jp) throws Throwable {
            System.out.println("======环绕前======");
    
            //执行方法
            Object proceed = jp.proceed();
    
            System.out.println("======环绕后======");
    
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 将AnnotationPointCut类注册到Spring中,即applicationContext.xml中
    
    <bean id="AnnotationPointCut" class="com.wei.diy.AnnotationPointCut"/>
    
    
    
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • MyTest测试类
    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
            //动态代理的是接口
            UserService userService = (UserService) context.getBean("userService");
            userService.delete();
    
        }
    }
    
    /*
    执行结果:
    ======环绕前======
    ======方法执行前======
    删除了一个用户
    ======环绕后======
    ======方法执行后======
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    🌼 结语:创作不易,如果觉得博主的文章赏心悦目,还请——点赞👍收藏⭐️评论📝冲冲冲🤞


  • 相关阅读:
    【2023】Git版本控制-远程仓库详解
    C#经典十大排序算法(完结)
    缓存选型:Redis or MemCache
    web前端面试题附答案041 - 曾经一个百度面试官问我,localStorage可以存对象吗?
    广和通5G/4G/NB-IoT智慧水务一体化联网解决方案精准加码水利数智化
    Asp-Net-Core学习笔记:单元测试和集成测试
    .net Framwork请求https携带客户端证书
    Hive数据库日期格式化
    【校招VIP】【约起来】高校大学生自己的商业项目|产品脑图的重要性:活动模型的细节
    集合在多线程下安全问题
  • 原文地址:https://blog.csdn.net/weixin_62765017/article/details/127612410