代码编织梦想

今日内容

1. 代理设计模式

静态代理模式
    前提
        代理角色和真实角色继承同一个类
    理解
        静态代理模式相当于在代理角色中,调用真实角色
            -真实角色只完成业务操作
            -代理角色完成增强业务-边角料
            -最后调用代理角色即可
package com.szr.service;
​
/**
 * 用户业务接口
 */
public interface UserService {
    /**
     * 获取用户信息
     * @return 返回用户信息
     */
    String getUser();
}
package com.szr.service.impl;
​
import com.szr.service.UserService;
​
/**
 * 用户业务接口实现类--真实角色
 */
public class UserServiceImpl implements UserService {
    /**
     * 获取用户信息
     * @return 返回用户信息
     */
    @Override
    public String getUser() {
        return "获取到用户信息了--钟离";
    }
}
package com.szr.staticProxy;
​
import com.szr.service.UserService;
​
/**
 * 用户静态代理角色-代理角色帮助完成增强业务
 */
public class UserStaticProxy implements UserService {
    //声明业务接口,后面用真实角色实现,代理角色调用
    private UserService userService ;
    //用真实角色来实现-这里替换的是真实角色的对象,方便调用
    public UserStaticProxy(UserService userService){
        this.userService = userService ;
    }
    @Override
    public String getUser() {
        //完成增强业务--比如用户查阅权限校验
        System.out.println("已完成对用户的权限校验");
        //实现真实业务
        String user = userService.getUser();
        //完成增强业务--比如记录操作
        System.out.println("已完成对查阅的记录");
        return user;
    }
}
/**
 * 对静态代理的测试
 */
@Test
public void StaticProxyTest(){
    //创建真实对象的实例
    UserService userService = new UserServiceImpl() ;
    //调用代理角色--传入真实角色对象,完成替换
    UserService userService1 = new UserStaticProxy(userService);
    //调用代理角色方法--里面的逻辑是,代理角色再调用真实角色
    String user = userService1.getUser();
    System.out.println(user);
    /*
    已完成对用户的权限校验
    已完成对查阅的记录
    获取到用户信息了--钟离
     */
}
jdk动态代理模式
    前提
        必须有一个接口,因为jdk动态代理是基于接口进行的
    理解
        代理模式都是先访问代理角色,再由代理角色访问真实角色,有真实角色反馈结果,再由代理角色反馈结果
        jdk动态代理是拦截器和反射共同进行的
            -必须实现InvocationHandler接口--获取真实角色的方法
            -使用Proxy.newProxyInstance(
                代理类要实现的接口的类加载器  ClassLoader loader,
                代理类要实现的接口列表 Class<?>[] interfaces,
                代理处理程序,代理角色具体内容 InvocationHandler handler
            )--获取代理角色对象,在调用方法
package com.szr.jdkProxy;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
​
/**
 * jdk动态代理必须实现InvocationHandler接口--相当于代理角色
 */
public class UserJdkProxy implements InvocationHandler {
    //声明任意对象,最后替换成需要完成的真实角色的对象
    private Object object ;
    public UserJdkProxy(Object object){
        this.object = object ;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理角色完成代理业务
        System.out.println("已经完成用户权限校验");
        //通过对真实角色对象的利用,通过反射的方式获取真实角色的方法
        Object obj = method.invoke(object, args);
        //代理角色完成业务增强
        System.out.println("已经完成日志记录");
        return obj;
    }
}
/**
 * jdk动态代理测试
 */
@Test
public void JdkProxyTest(){
    //创建真实角色对象
    UserService userService = new UserServiceImpl();
    //创建jdkProxy对象,返回的是目标角色-真实角色的方法
    UserJdkProxy handler = new UserJdkProxy(userService);
    //获取代理对象
    UserService userService1 = (UserService) Proxy.newProxyInstance(
            userService.getClass().getClassLoader(),
            userService.getClass().getInterfaces(),
            handler
    );
    //调用方法
    String user = userService1.getUser();
    System.out.println(user);
    /*
        已经完成用户权限校验
        已经完成日志记录
        获取到用户信息了--钟离
     */
}
cglib动态代理模式
        基于子类实现代理模式
        实现接口 cglib提供的InvocationHandler
        需要导入cglib.jar包
    步骤
        1)创建增强类,通过增强类对真实角色产生代理
        2)使用增强类对指定的类型的Class产生代理-设置目标类型
        3)设置回调-当前类对象的地址值引用
        4)通过增强类创建代理实例
package com.szr.cglibProxy;
​
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.InvocationHandler;
​
import java.lang.reflect.Method;
​
/**
 * cglib完成动态代理
 */
public class cglibProxy implements InvocationHandler {
    //还是传入真实角色对象替换对象
    private Object object ;
    public cglibProxy(Object object){
        this.object = object ;
    }
​
    //自定义一个方法完成对代理角色的创建
    public Object getObject(){
        //创建增强类
        Enhancer enhancer = new Enhancer();
        //使用增强类对指定类型的Class产生代理
        enhancer.setSuperclass(object.getClass());
        //设置回调-this当前类地址引用
        enhancer.setCallback(this);
        //使用增强类创建代理实例
        Object obj = enhancer.create();
        return obj ;
    }
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        //完成代理角色增强业务
        System.out.println("已经校验过权限");
        Object invoke = method.invoke(object, objects);
        System.out.println("已经记录到日志");
        return invoke;
    }
}
@Test
public void CglibProxyTest(){
    //创建真实对象
    UserService userService = new UserServiceImpl();
    //创建cglib的handler对象
    cglibProxy cglib = new cglibProxy(userService);
    UserService userService1 = (UserService) cglib.getObject();
    String user = userService1.getUser();
    System.out.println(user);
    /*
        已经校验过权限
        已经记录到日志
        获取到用户信息了--钟离
     */
}

2. SpringAOP技术

SpringAOP
    Spring核心技术之一
    理解
        就是Spring方式的代理模式
    思路
        使用xml配置方式/注解配置方式
        再Spring配置文件中管理对应类/开启全局注解扫描
        测试类中使用即可
xml文件配置方式
    分开配置方式
        自定义类继承对应的接口
            -业务前执行接口-MethodBeforeAdvice
            -业务后执行接口-AfterReturningAdvice
            -业务报错执行接口-ThrowsAdvice
    合在一起配置方式
            -业务环绕执行接口-MethodInterceptor-相当于将上面的执行步骤合在一起
    配置Spring通知 切点以及通知类型
        aop:config
            aop:advisor
                    属性advice-ref:指定通知类型 上面id标识一致
                    属性pointcut:切点表达式:SpringAOP方式找到业务方法进行方法增强
                    切点表达式语法:
                        第一个*必须写:固定语法格式
                        第二个*和第一个*中间有一个空格的
                        第三个*: 包名的第一个包  
                        第四个*:  具体业务接口所在的包名service
                        第五个*:  接口实现类型的包名impl
                        第六个*: 指定的类名
                        第七个*: 指定的方法名
                        (..):不明确参数使用(..)
    组装切面
                aop:aspect
                        id="指定唯一标识"
                        ref="关联切面类"
​
                     配置通知同时指定切点表达式,这样很麻烦!
                     spring提供的切点定义 aop:pointcut
                                            id="唯一标识"
                                            pointcut:切点表达式
注解配置方式
    开启SpringAOP注解方式通过 切面给业务功能进行增强,开启注解让Spring扫描AOP相关的注解
        <aop:aspectj-autoproxy/>
    定义切面类,使用注解的方式
        分开配置
            将所有的业务接口分开织入切面类,单独成每一个方法,单独使用注解
        合在一起配置
            定义一个环绕通知方法-将所有业务增强都用进去,使用一个环绕注解

分开配置方式 自定义类继承对应的接口 -业务前执行接口-MethodBeforeAdvice -业务后执行接口-AfterReturningAdvice -业务报错执行接口-ThrowsAdvice

package com.szr.springAOC;
​
import org.springframework.aop.MethodBeforeAdvice;
​
import java.lang.reflect.Method;
//执行业务前通知
public class BeforeHandler implements MethodBeforeAdvice {
​
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("已经进行权限校验!");
    }
}
package com.szr.springAOC;
​
import org.springframework.aop.AfterReturningAdvice;
​
import java.lang.reflect.Method;
//执行业务后通知
public class AfterHandler implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("已经记录在日志!");
    }
}
<?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
        https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
​
    <!--将用户实现类,真实角色管理起来-->
    <bean id="userService" class="com.szr.service.impl.UserServiceImpl"/>
    <!--管理执行前通知-->
    <bean id="beforeHandler" class="com.szr.springAOC.BeforeHandler"></bean>
    <!--管理执行后通知-->
    <bean id="afterHandler" class="com.szr.springAOC.AfterHandler"></bean>
​
    <!--配置Spring通知 切点以及通知类型-->
    <aop:config>
        <!--配置执行前通知 关联执行前通知类 后面是切点-就是要执行的内容,在执行这个内容的时候切入-->
        <aop:advisor advice-ref="beforeHandler" pointcut="execution(* *.*.service.impl.*.*(..))"></aop:advisor>
        <!--配置执行后通知 关联执行后通知类-->
        <aop:advisor advice-ref="afterHandler" pointcut="execution(* *.*.service.impl.*.*(..))"></aop:advisor>
    </aop:config>
</beans>
/**
​
 * SpringAOC普通版测试
   */
   @Test
   public void SpringAOCCommonTest(){
   ClassPathXmlApplicationContext context =
           new ClassPathXmlApplicationContext("spring-config.xml");
   UserService userService = (UserService) context.getBean("userService");
   String user = userService.getUser();
   System.out.println(user);
   /*
       已经进行权限校验!
       已经记录在日志!
       获取到用户信息了--钟离
    */
   }

合在一起配置方式 -业务环绕执行接口-MethodInterceptor-相当于将上面的执行步骤合在一起

package com.szr.springAOC;
​
​
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
​
import java.lang.reflect.Method;
//普通环绕通知,将分散的通知整合
public class MyRound implements MethodInterceptor {
​
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        //准备执行前通知
        System.out.println("已经校验过了");
        //产生代理实例,反射调用业务方法
        Object obj = invocation.proceed();
        //准备执行后通知
        System.out.println("已经记录在日志");
        return obj;
    }
}
<?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
        https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
​
    <!--将用户实现类,真实角色管理起来-->
    <bean id="userService" class="com.szr.service.impl.UserServiceImpl"/>
    <!--管理环绕通知类-->
    <bean id="myRound" class="com.szr.springAOC.MyRound"></bean>
​
    <!--配置Spring通知 切点以及通知类型-->
    <aop:config>
        <!--配置环绕通知-->
        <aop:advisor advice-ref="myRound" pointcut="execution(* *.*.service.impl.*.*(..))"></aop:advisor>
    </aop:config>
</beans>
/**
 * SpringAOC普通方式整合版
 */
@Test
public void SpringAOCRound(){
    ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("spring-config.xml");
    UserService userService = (UserService) context.getBean("userService");
    String user = userService.getUser();
    System.out.println(user);
    /*
        已经校验过了
        已经记录在日志
        获取到用户信息了--钟离
     */
}

定义切面类,使用注解的方式 分开配置 将所有的业务接口分开织入切面类,单独成每一个方法,单独使用注解

package com.szr.springAOC;
​
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
​
//切面类,注解使用
@Component
@Aspect//标记为切面类
public class MyAspect {
​
    //定义一个方法,指定切点表达式
    @Pointcut("execution(* *.*.service.impl.*.*(..))")
    public void PointCut(){}
​
    //定义一个方法,执行前通知,直接将切点表达式的方法名放进去
    @Before("PointCut()")
    public void BeforeHandler(){
        System.out.println("真的已经校验过权限了");
    }
​
    //定义一个方法,执行后通知,直接将切点表达式的方法名放进去
    @AfterReturning("PointCut()")
    public void AfterHandler(){
        System.out.println("真的已经记录在日志了");
    }
}
<?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
        https://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
​
    <!--将用户实现类,真实角色管理起来-->
    <bean id="userService" class="com.szr.service.impl.UserServiceImpl"/>
    <!--管理执行前通知-->
    <bean id="beforeHandler" class="com.szr.springAOC.BeforeHandler"></bean>
    <!--管理执行后通知-->
    <bean id="afterHandler" class="com.szr.springAOC.AfterHandler"></bean>
    <!--管理环绕通知类-->
    <bean id="myRound" class="com.szr.springAOC.MyRound"></bean>
    <!--管理环绕通知类注解方式-->
    <bean id="myAspect" class="com.szr.springAOC.MyAspect"></bean>
​
    <!--开启SpringAOP注解方式通过 切面给业务功能进行增强,开启注解让Spring扫描AOP相关的注解-->
    <aop:aspectj-autoproxy/>
</beans>
/**
 * SpringAOC注解使用方式
 */
@Test
public void SpringAOCAspect(){
    ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("spring-config.xml");
    UserService userService = (UserService) context.getBean("userService");
    String user = userService.getUser();
    System.out.println(user);
    /*
        真的已经校验过权限了
        真的已经记录在日志了
        获取到用户信息了--钟离
     */
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_53118395/article/details/128842929

3.代理模式、桥接模式、装饰器模式、适配器模式-爱代码爱编程

代理模式 在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能 原来的实现,代码侵入性比较强 public class UserController { //..

spring integration开篇:说明-爱代码爱编程

系列文章目录 …TODO spring integration开篇:说明 …TODO spring integration使用:消息路由 spring integration开篇:说明 系列文章目录前言ent

mybatis框架如何实现数据查询?有几种方法?-爱代码爱编程

在实际开发中,查询操作通常都会涉及到单条数据的精确查询,以及多条数据的模糊查询。那么使用MyBatis框架是如何进行这两种查询的呢?接下来,本小节将讲解下如何使用MyBatis框架根据客户编号查询客户信息,以及根据客户名模糊查询客户信息。 1.根据客户编号查询客户信息 根据客户编号查询客户信息主要是通过查询客户表中的主键(这里表示唯一的客户编号)来

2023年深圳java培训机构排名,不看后悔系列!-爱代码爱编程

不忘初心,方得始终。2023,继续战斗!想要学习Java的小伙伴们看过来~深圳Java培训机构排名最新排行榜来了!靠谱的Java培训机构都在这里,总有一个你喜欢的,总能选出一个合适你的,快拿出小本本记下这条保命信息。 一、深圳动力节点 动力节点之所以在榜首,是因为动力节点是专门教Java的培训机构。自成

国密算法(sm2)java语言的实现:利用bcprov库来实现sm2算法,非对称算法-爱代码爱编程

SM2算法简介 随着密码技术和计算机技术的发展,目前常用的1024位RSA算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2椭圆曲线算法替换RSA算法。 SM2是非对称加密算法;SM2是基于椭圆曲线密码

设计模式之代理模式-爱代码爱编程

一.什么是代理模式 代理模式是某个对象提供一个代理对象,并且由代理对象控制对原对象的访问,在不修改被代理对象的前提下提供额外的功能操作。 二.为什么要代理模式 代理模式职责清晰,可扩展性高,能很好的提供访问控制,类似生活中常见的中介。 代理类主要为被代理类预处理消息,过滤消息,把消息转发给委托类,以及对返回结果的处理。代理类本身不真正实现业务,而是

intellij idea 闪退的解决办法-爱代码爱编程

场景 最近这idea闪退频率又多了不少 以前 几天一闪退 现在 一天N多次闪退 如下图 看这崩溃日志 这怎么顶 解决办法 查看崩溃日志 日志 1 日志2 日志3 可以看出现在生效的参数 Command Lin

高级spring之jdk 动态代理进阶-爱代码爱编程

演示1 - 模拟 jdk 动态代理 public class A12 { interface Foo { void foo(); int bar(); } static class Target implements Foo { public void foo() {

redis主从架构 | 黑马redis高级篇-爱代码爱编程

目录 一、搭建主从架构 1、为什么要搭建 2、准备实例和配置 3、启动 4、开启主从关系 二、 数据同步原理 1、全量同步 2、命令传播 3、增量同步 三、常见面试题 一、搭建主从架构 1、为什么要搭建 如果服务器发生了宕机,由于数据恢复是需要点时间,那么这个期间是无法服务新的请求的 如果这台服务器的硬盘出现了故障,可能数据就

go语言进阶和依赖管理(二)——并发和依赖管理-爱代码爱编程

文章目录 一、本文重点内容:二、详细知识点介绍:1、并发和并行并发:并行:结论: 2、Go的协程协程:线程: 3、协程通信方式一:使用通道交换数据方式二:使用共享内存完成数据交换 4、协程通道

代理模式浅谈和在vue中的使用-爱代码爱编程

当本体处于保护、缓存、虚拟或者过滤等情况下时,一个数据不适合被访问或者一个方法不能被直接调用,可以采用代理模式,先创建一个代理(本体对象或者方法的替身),作为访问者和本体之间的中介或者桥梁。 本体访问和代理访问的

非dbca静默安装~字符集设定-爱代码爱编程

./runInstaller -silent -ignorePrereq -responseFile db_name=yqzldb control_files=/data/app/oracle/oradata/contro

spring 中 mybaits 的一级缓存失效_mybatis 一级缓存失效-爱代码爱编程

mybatis 的一级缓存 简单回顾下mybatis的一级缓存 本质上是一个基于map实现的内存级别的缓存,默认开启,生命周期是 sqlsession 级别的 为什么会失效 其实这个问题反向分析一下就会有思路了,一级缓存默

图文详解 java 泛型,写得太好了!-爱代码爱编程

一、泛型的引入 我们都知道,继承是面向对象的三大特性之一,比如在我们向集合中添加元素的过程中add()方法里填入的是Object类,而Object又是所有类的父类,这就产生了一个问题——添加的类型无法做到统一 由此就可能产生在遍历集合取出元素时类型不统一而报错问题。 例如:我向一个ArrayList集合中添加Person类的对象,但是不小心手

kotlin 空指针检查_android kotlin 判空-爱代码爱编程

据机构统计,Android系统崩溃率最高的异常是空指针异常(NullPointerException) 是因为这是一种不受编译器检查,而靠程序员主动判断的避免的异常 如果函数传入一个null参数,很可能会发生空指针异常

javase总复习_javase复习-爱代码爱编程

一、 填空题(共 20 个题目,总计 20 分) 1. Java application 中的主类需要包含 main 方法,main 方法的返回类型是void 。 2. 移位运算符可以起到对操作数乘以 2 或者除以 2 的作用,那么操作数除以 2 的移位 操作的运算符是 >> 。 3. System.out.println

spring事务执行流程分析_2(xml文件解析)_xml文件怎么执行的-爱代码爱编程

调用链路 org.springframework.context.support.AbstractApplicationContext#refresh -> org.springframework.context.s