ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring框架(代理模式)

2021-11-29 19:30:16  阅读:91  来源: 互联网

标签:框架 Spring Object 代理 System org import public


目录

1. 代理模式

1.1 创建项目

1.1.1创建项目

1.1.2 完成入门代码测试

1.1.3 编辑UserService

1.1.4 业务层如何控制事务

1.1.4 业务代码-问题说明

1.2 代理机制

1.2.1 代理模式特点

1.2.1 代理特点

1.3 动态代理-JDK模式

1.3.1 JDK代理的说明

1.3.2 编辑代理类 

 1.3.3 编辑测试类

1.4 动态代理-JDK模式案例

1.4.1 编辑代理对象

 1.4.2 编辑测试方法

1.5 动态代理-CGLIB代理

1.5.1 CGLIB说明

1.5.2 CGLIB代理模式

1 .5.3 CGLIB代理测试类

 1.6 关于JDK代理和CGlib代理总结(高程/架构)!!!

2. Spring AOP介绍

2.1 创建项目

2.1.1 基本结构

 2.1.2 层级代码结构

2.1.3 层级代码结构 

2.2 AOP

2.2.1 AOP介绍

2.2.2 AOP 入门案例

2.3 常见通知类型


1. 代理模式

1.1 创建项目

1.1.1创建项目

在这里插入图片描述

1.1.2 完成入门代码测试

在这里插入图片描述

1.1.3 编辑UserService

1.1.3.1 编辑Service接口

package com.jt.service;

public interface UserService {

    void addUser();
}

 1.1.3.2 编辑ServiceImpl实现类

package com.jt.service;

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService{

    @Override
    public void addUser() {
        System.out.println("新增用户");
    }
}

1.1.4 业务层如何控制事务

事务: 可以保证数据的/原子性/一致性/持久性/隔离性.
说明: 业务层操作时,需要考虑数据库的事务.代码结构如下:

package com.jt.service;

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService{

    @Override
    public void addUser() {
        try {
            System.out.println("开启数据库事务");
            System.out.println("新增用户");
            int a = 1/0;
            System.out.println("提交数据库事务");
        }catch (Exception e){
            System.out.println("事务回滚");
        }
    }
}

1.1.4 业务代码-问题说明

  1. 如果有多个方法,则每个方法都需要控制事务. 代码重复率高.
  2. 业务层service,应该只处理业务,不要和事务代码耦合在一起.否则扩展性不好,耦合性高.

如何解决: 采用代理机制解决.

1.2 代理机制

1.2.1 代理模式特点

说明: 一般采用代理模式,主要的目的就是为了解耦.将公共的通用的方法(功能/业务)放到代理对象中. 由业务层专注于业务执行即可.

1.2.1 代理特点

  1. 为什么使用代理? 因为自己不方便(没有资源)
  2. 代理的作用? 代理要解决(扩展)某些实际问题.
  3. 用户最终执行目标方法!!!

在这里插入图片描述

1.3 动态代理-JDK模式

1.3.1 JDK代理的说明

  1. JDK代理模式是java原生提供的API,无需导包
  2. JDK代理要求: 被代理者必须 要么是接口,要么实现接口
  3. 灵活: 代理对象应该看起来和被代理者 一模一样!!! (方法相同)

1.3.2 编辑代理类 

package com.jt.proxy;

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

public class JDKProxy {

    //传入target目标对象获取代理对象的
    //利用代理对象 实现方法的扩展
    public static Object getProxy(Object target){
        //1.获取类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
        //2.获取接口数组类型
        Class[] interfaces = target.getClass().getInterfaces();
        //3.代理对象执行方法时的回调方法(代理对象调用方法时,执行InvocationHandler)
        return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler(target));
    }

    //要求必须传递目标对象
    public static InvocationHandler invocationHandler(Object target){
       return new InvocationHandler() {
           @Override
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               System.out.println("事务开启");
               //获取目标方法的返回值
               Object result = method.invoke(target,args);
               System.out.println("事务提交");
               return result;
           }
       };
    }
}

 1.3.3 编辑测试类

package com.jt;

import com.jt.config.SpringConfig;
import com.jt.proxy.JDKProxy;
import com.jt.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring {

    @Test
    public void demo1(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取目标对象
        UserService userService = context.getBean(UserService.class);
        //userService.addUser();
        //获取代理对象
        UserService proxy = (UserService) JDKProxy.getProxy(userService);
        //代理对象执行方法, 调用invoke方法
        proxy.addUser();
    }
}

 

1.4 动态代理-JDK模式案例

需求: 要求大家计算addUser()方法的运行时间? 要求采用动态代理的方式完成.

1.4.1 编辑代理对象

 public static Object getTimePorxy(Object target){
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class[] interfaces = target.getClass().getInterfaces();
        return Proxy.newProxyInstance(classLoader,interfaces,invocationHandlerTime(target));
    }

    //要求必须传递目标对象
    public static InvocationHandler invocationHandlerTime(Object target){
        return new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //开始时间
                long startTime = System.currentTimeMillis();
                //让目标方法执行 结果
                Object result = method.invoke(target,args);
                long endTime = System.currentTimeMillis();
                System.out.println("耗时:"+(endTime - startTime));
                return result;
            }
        };
    }

 1.4.2 编辑测试方法

 

package com.jt;

import com.jt.config.SpringConfig;
import com.jt.proxy.JDKProxy;
import com.jt.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring {

    @Test
    public void demo1(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取目标对象
        UserService userService = context.getBean(UserService.class);
        System.out.println(userService.getClass());
        //userService.addUser();
        //获取代理对象
        UserService proxy = (UserService) JDKProxy.getTimePorxy(userService);
        System.out.println(proxy.getClass());
        //代理对象执行方法, 调用invoke方法
        proxy.addUser();
    }
}

1.5 动态代理-CGLIB代理

1.5.1 CGLIB说明

jdk代理: 要求必须有/实现接口. 如果没有接口,则JDK代理不能正常执行.
cglib代理: 要求被代理者有无接口都可以. 代理对象是目标对象的子类 重写子类方法

1.5.2 CGLIB代理模式

package com.jt.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGlibProxy {

    public static Object getProxy(Object target){
        //1.创建增强器对象
        Enhancer enhancer = new Enhancer();
        //2.设定父级 目标对象
        enhancer.setSuperclass(target.getClass());
        //3.定义回调方法 代理对象执行目标方法时调用
        enhancer.setCallback(getMethodInterceptor(target));
        //4.创建代理对象
        return enhancer.create();
    }
    //需要传递target目标对象
    public static MethodInterceptor getMethodInterceptor(Object target){
        return new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("事务开始");
                //执行目标方法
                Object result = method.invoke(target,args);
                System.out.println("事务提交");
                return result;
            }
        };
    }
}

1 .5.3 CGLIB代理测试类

@Test
    public void demo2(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取目标对象
        UserService userService = context.getBean(UserService.class);
        UserService proxy = (UserService) CGlibProxy.getProxy(userService);
        System.out.println(proxy.getClass());
        proxy.addUser();
    }

 在这里插入图片描述

 1.6 关于JDK代理和CGlib代理总结(高程/架构)!!!

1. JDK要求必须有或者实现接口, cglib有无接口都可以创建代理对象.代理对象是目标对象的子类
2. JDK代理工具API: Proxy.newProxyInstance(类加载器,接口数组,invocationHandler接口)
3. CGlib代理工具API: Enhancer 增强器对象 获取代理对象 enhancer.create(); 回调接口
MethodInterceptor接口
4. JDK中执行目标方法
-method.invoke(target,args);
CGlib中执行目标方法
-method.invoke(target,args);
 

2. Spring AOP介绍

2.1 创建项目

2.1.1 基本结构

 在这里插入图片描述

 2.1.2 层级代码结构

在这里插入图片描述

2.1.3 层级代码结构 

  <!--引入AOPjar包文件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.2 AOP

2.2.1 AOP介绍

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

总结: Spring中的AOP 利用代理对象在不修改源代码的条件下,对方法进行扩展.
在这里插入图片描述

 

2.2.2 AOP 入门案例

2.2.2.1 编辑配置类

@Configuration
@ComponentScan("com.jt") //包扫描
@EnableAspectJAutoProxy  //开启AOP
public class SpringConfig {


}

 2.2.2.2 编辑切面类

package com.jt.aop;

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

@Component  //将给类交给Spring容器管理  !!!
@Aspect     //标识该类是一个切面
public class SpringAOP {
    /**
     * 知识回顾: AOP利用动态代理扩展目标方法.
     * 公式:    切面 = 切入点表达式 + 通知方法
     * 切入点表达式: 如果目标对象满足切入点表达式的判断(if),则spring自动为其创建代理对象
     * 通知方法:  对目标方法进行扩展的封装方法.
     * 目标对象的bean的ID: userServiceImpl
     * 切入点表达式:
     *      1. bean("bean的ID")
     * AOP规则:  如果目标对象满足切入点表达式,则执行通知方法
     */
    @Pointcut("bean(userServiceImpl)")
    public void pointcut(){

    }

    //前置通知: 在目标方法执行之前执行.
    @Before("pointcut()")
    public void before(){
        System.out.println("我是前置通知!!!!");
    }
}

2.2.2.3 编辑测试类

package com.jt;

import com.jt.config.SpringConfig;
import com.jt.service.UserService;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class TestSpring {

    @Test
    public void demo1(){
        ApplicationContext context =
                new AnnotationConfigApplicationContext(SpringConfig.class);
        //本来是目标对象,只不过与切入点表达式匹配,则动态生成代理对象.
        UserService userService = context.getBean(UserService.class);
        System.out.println(userService.getClass());
        //由于是代理对象,所以方法可以扩展
        userService.addUser();
    }
}

2.3 常见通知类型

package com.jt.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component  //将给类交给Spring容器管理  !!!
@Aspect     //标识该类是一个切面
public class SpringAOP {
    /**
     * 知识回顾: AOP利用动态代理扩展目标方法.
     * 公式:    切面 = 切入点表达式 + 通知方法
     * 切入点表达式: 如果目标对象满足切入点表达式的判断(if),则spring自动为其创建代理对象
     * 通知方法:  对目标方法进行扩展的封装方法.
     * 目标对象的bean的ID: userServiceImpl
     * 切入点表达式:
     *      1. bean("bean的ID")
     * AOP规则:  如果目标对象满足切入点表达式,则执行通知方法
     */
    @Pointcut("bean(userServiceImpl)")
    public void pointcut(){

    }

    //1.前置通知: 在目标方法执行之前执行.
    @Before("pointcut()")
    public void before(){
        System.out.println("我是前置通知!!!!");
    }

    //2.后置通知: 在目标方法执行之后执行
    @AfterReturning("pointcut()")
    public void afterReturn(){
        System.out.println("我是后置通知!!!!");
    }

    //3.异常通知: 目标方法执行报错时,执行该通知
    @AfterThrowing("pointcut()")
    public void afterThrowing(){
        System.out.println("我是异常通知!!!!");
    }

    //4.最终通知: 目标方法之后都要执行的通知
    @After("pointcut()")
    public void after(){
        System.out.println("最终通知都要执行");
    }

    //5.重点掌握 环绕通知: 在目标方法执行前后都要执行. 控制目标方法
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知执行前!!!!");
        //底层调用动态代理的invoke方法,执行目标方法
        Object result = joinPoint.proceed();
        System.out.println("环绕通知执行后!!!!");
        return result;
    }
}

标签:框架,Spring,Object,代理,System,org,import,public
来源: https://blog.csdn.net/weixin_44591613/article/details/121616979

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有