Spring AOP 学习(动态代理、JdbcTemplate、Junit)

news2024/12/24 7:47:01

动态代理

Proxy  jdk动态代理,面向接口

cglib   第三方动态代理,面向父类

jdk动态代理

public class Test1 {
    public static void main(String[] args) {
        Dinner dinner=new Person("张三");
        // 通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强
//        ClassLoader loader,被代理的对象的类加载器
        ClassLoader classLoader = dinner.getClass().getClassLoader();
//        Class<?>[] interfaces,被代理对象所实现的所有接口
        Class[] interaces= dinner.getClass().getInterfaces();
//        InvocationHandler h,执行处理器对象,专门用于定义增强的规则
        InvocationHandler handler = new InvocationHandler(){
            // invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                Object proxy, 代理对象
//                Method method,被代理的方法
//                Object[] args,被代理方法运行时的实参
                Object res=null;
               if(method.getName().equals("eat")){
                   System.out.println("饭前洗手");
                   // 让原有的eat的方法去运行
                   res =method.invoke(dinner, args);
                   System.out.println("饭后刷碗");
               }else{
                   // 如果是其他方法,那么正常执行就可以了
                   res =method.invoke(dinner, args);
               }
                return res;
            }
        };
        Dinner dinnerProxy =(Dinner) Proxy.newProxyInstance(classLoader,interaces,handler);
        //dinnerProxy.eat("包子");
        dinnerProxy.drink();
    }
}
interface Dinner{
    void eat(String foodName);
    void drink();
}
class Person implements Dinner{
    private String name;
    public Person(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝茶");
    }
}
class Student implements Dinner{
    private String name;
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void eat(String foodName) {
        System.out.println(name+"正在食堂吃"+foodName);
    }
    @Override
    public void drink( ) {
        System.out.println(name+"正在喝可乐");
    }
}

不修改原有代码,或者没有办法修改原有代码的情况下,增强对象功能,使用代理对象代替原来的对象去完成功能,进而达到拓展功能的目的

JDK Proxy 动态代理是面向接口的动态代理,一定要有接口和实现类的存在,代理对象增强的是实现类实现接口时重写的方法 

生成的代理对象只能转换成接口,不能转换成被代理类(上面只能是Dinner,不能是Person或Student)

代理对象只能增强接口中定义的方法, 实现类中其他和接口无关的方法是无法增强的

代理对象只能读取到接口中方法上的注解,不能读取到实现类方法上的注解

cglib动态代理

面向父类的,和接口没有直接关系

不仅仅可以增强接口中定义的方法,还可以增强一个类的其他方法

可以读取父类中方法上的所有注解

public class Test1 {
    @Test
    public void testCglib(){
        Person person =new Person();
        // 1 获得一个Enhancer对象
        Enhancer enhancer=new Enhancer();
        // 2 设置父类字节码
        enhancer.setSuperclass(person.getClass());
        // 3 获取MethodIntercepter对象 用于定义增强规则
        MethodInterceptor methodInterceptor=new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                /*Object o,  生成之后的代理对象 personProxy
                Method method,  父类中原本要执行的方法  Person>>> eat()
                Object[] objects, 方法在调用时传入的实参数组
                MethodProxy methodProxy  子类中重写父类的方法 personProxy >>> eat()
                */
                Object res =null;
                if(method.getName().equals("eat")){
                    // 如果是eat方法 则增强并运行
                    System.out.println("饭前洗手");
                    res=methodProxy.invokeSuper(o,objects);
                    System.out.println("饭后刷碗");
                }else{
                    // 如果是其他方法 不增强运行
                    res=methodProxy.invokeSuper(o,objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法
                }
                return res;
            }
        };
        // 4 设置methodInterceptor
        enhancer.setCallback(methodInterceptor);
        // 5 获得代理对象
        Person personProxy = (Person)enhancer.create();
        // 6 使用代理对象完成功能
        personProxy.eat("包子");
    }
}
class Person  {
    public Person( ) {
    }
    public void eat(String foodName) {
        System.out.println("张三正在吃"+foodName);
    }
}

AOP概念

AOP切面编程一般可以帮助我们在不修改现有代码的情况下,对程序的功能进行拓展,往往用于实现日志处理,权限控制,性能检测,事务控制


AOP实现的原理就是动态代理

在有接口的情况下,使用JDK动态代理,在没有接口的情况下使用cglib动态代理

开闭原则:对于扩展是开放的,但是对于修改是封闭的

连接点 Joint point

类里面那些可以被增强的方法,这些方法称之为连接点(可以被增强,不一定真的被增强了)

 切入点 Pointcut

实际被增强的方法,称之为切入点

通知 Advice

实际增强的逻辑部分称为通知 (增加的功能)

通知类型: 1 前置通知 2 后置通知 3 环绕通知 4 异常通知 5 最终通知

目标对象 Target

被增强功能的对象(被代理的对象)

织入 Advice 的目标对象

切面Aspect

表现为功能相关的一些advice方法放在一起声明成的一个Java类

织入 Weaving

创建代理对象并实现功能增强的声明并运行过程

切入点表达式

execution([权限修饰符][返回值类型][类的全路径名][方法名](参数 列表) )

execution(* com.msb.dao.UserDaoImpl.add(..))  //指定切点为UserDaoImpl.add方法 

execution(* com.msb.dao.UserDaoImpl.*(..))      //指定切点为UserDaoImpl.所有的方法 

execution(* com.msb.dao.*.*(..))                         //指定切点为dao包下所有的类中的所有的方法 

execution(* com.msb.dao.*.add(..))                     // 指定切点为dao包下所有的类中的add的方法 

execution(* com.msb.dao.*.add*(..))                   // 指定切点为dao包下所有的类中的add开头的方法 

通知类型

前置通知@Before

切点方法执行之前先执行的功能,参数列表可以用JoinPoint接收切点对象

后置通知@After

方法执行之后要增强的功能,无论切点方法是否出现异常都会执行的方法(最终通知)

返回通知@AfterReturning

切点方法正常运行结束后增强的功能,

    @AfterReturning( value = "execution(* com.msb.dao.UserDaoImpl.add(..))",returning = "res")
    public void methodAfterReturning(JoinPoint joinPoint,Object res){
        System.out.println("AfterReturning invoked");
    }

如果方法运行过程中出现异常,则该功能不运行

参数列表可以用 JoinPoint joinPoint接收切点对象
可以用Object res接收方法返回值,需要用returning指定返回值名称

异常通知 @AfterThrowing

切点方法出现异常时运行的增强功能,如果方法运行没有出现异常,则该功能不运行

参数列表可以用Exception ex接收异常对象 需要通过throwing指定异常名称

    @AfterThrowing( value = "execution(* com.msb.dao.UserDaoImpl.add(..))",throwing = "ex")
    public void methodAfterThrowing(Exception ex){
        System.out.println("AfterThrowing invoked");
    }

环绕通知@Around

在切点方法之前和之后都进行功能的增强

需要在通知中定义方法执行的位置,并在执行位置之前和之后自定义增强的功能

方法列表可以通过ProceedingJoinPoint获取执行的切点

通过proceedingJoinPoint.proceed()方法控制切点方法的执行位置

proceedingJoinPoint.proceed()方法会将切点方法的返回值获取到,可以用来做后续处理

我们在环绕通知的最后需要将切点方法的返回值继续向上返回,否则切点方法在执行时接收不到返回值


    @Around("execution(* com.msb.dao.UserDaoImpl.add(..))")
    public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("aroundA invoked");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("aroundB invoked");
        return proceed;
    }

公共切点

定义

    @Pointcut("execution(* com.msb.dao.*.add*(..))")
    public void addPointCut(){}

使用

@Before("addPointCut()")

通知顺序:@Around before =》@Before =》方法调用=》@AfterReturning/@AfterThrowing=》@After=》@Around after

 @Order

可以指定代理顺序,数字越小,越靠后被代理,也就是@Around before越先执行

@EnableAspectJAutoProxy(proxyTargetClass=true)

开启自动代理

使用aop需要开启包扫描和开启自动代理

JdbcTemplate

可以使用JdbcTemplate实现查询

// 查询个数
Integer empCount = jdbcTemplate.queryForObject("select count(1) from emp", Integer.class);
// 查询单个对象
BeanPropertyRowMapper<Emp> rowMapper =new BeanPropertyRowMapper<>(Emp.class);
Emp emp = jdbcTemplate.queryForObject("select * from emp where empno =?", rowMapper, empno);
        

插入 

        // 批量新增操作
        String sql ="insert into dept values(DEFAULT,?,?)";
        List<Object[]> args =new LinkedList<>();
        for (Dept dept : depts) {
            Object[] arg ={dept.getDname(),dept.getLoc()};
            args.add(arg);
        }
        return jdbcTemplate.batchUpdate(sql, args);

查看接口实现类

ctrl + h

事务

@Transactional注解放在类上,表示该类中所有方法都加事务

加了@Transactional注解后,该方法中两个dao操作会保持原子性

@Transactional的参数

public @interface Transactional {

	/**
	 * Alias for {@link #transactionManager}.
	 * @see #transactionManager
	 */
	@AliasFor("transactionManager")
	String value() default "";

	/**
	 * A <em>qualifier</em> value for the specified transaction.
	 * <p>May be used to determine the target transaction manager, matching the
	 * qualifier value (or the bean name) of a specific
	 * {@link org.springframework.transaction.TransactionManager TransactionManager}
	 * bean definition.
	 * @since 4.2
	 * @see #value
	 * @see org.springframework.transaction.PlatformTransactionManager
	 * @see org.springframework.transaction.ReactiveTransactionManager
	 */
	@AliasFor("value")
	String transactionManager() default "";

	/**
	 * The transaction propagation type.
	 * <p>Defaults to {@link Propagation#REQUIRED}.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()
	 */
	Propagation propagation() default Propagation.REQUIRED;

	/**
	 * The transaction isolation level.
	 * <p>Defaults to {@link Isolation#DEFAULT}.
	 * <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
	 * {@link Propagation#REQUIRES_NEW} since it only applies to newly started
	 * transactions. Consider switching the "validateExistingTransactions" flag to
	 * "true" on your transaction manager if you'd like isolation level declarations
	 * to get rejected when participating in an existing transaction with a different
	 * isolation level.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
	 * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
	 */
	Isolation isolation() default Isolation.DEFAULT;

	/**
	 * The timeout for this transaction (in seconds).
	 * <p>Defaults to the default timeout of the underlying transaction system.
	 * <p>Exclusively designed for use with {@link Propagation#REQUIRED} or
	 * {@link Propagation#REQUIRES_NEW} since it only applies to newly started
	 * transactions.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
	 */
	int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

	/**
	 * A boolean flag that can be set to {@code true} if the transaction is
	 * effectively read-only, allowing for corresponding optimizations at runtime.
	 * <p>Defaults to {@code false}.
	 * <p>This just serves as a hint for the actual transaction subsystem;
	 * it will <i>not necessarily</i> cause failure of write access attempts.
	 * A transaction manager which cannot interpret the read-only hint will
	 * <i>not</i> throw an exception when asked for a read-only transaction
	 * but rather silently ignore the hint.
	 * @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
	 * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
	 */
	boolean readOnly() default false;

	/**
	 * Defines zero (0) or more exception {@link Class classes}, which must be
	 * subclasses of {@link Throwable}, indicating which exception types must cause
	 * a transaction rollback.
	 * <p>By default, a transaction will be rolling back on {@link RuntimeException}
	 * and {@link Error} but not on checked exceptions (business exceptions). See
	 * {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)}
	 * for a detailed explanation.
	 * <p>This is the preferred way to construct a rollback rule (in contrast to
	 * {@link #rollbackForClassName}), matching the exception class and its subclasses.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}.
	 * @see #rollbackForClassName
	 * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
	 */
	Class<? extends Throwable>[] rollbackFor() default {};

	/**
	 * Defines zero (0) or more exception names (for exceptions which must be a
	 * subclass of {@link Throwable}), indicating which exception types must cause
	 * a transaction rollback.
	 * <p>This can be a substring of a fully qualified class name, with no wildcard
	 * support at present. For example, a value of {@code "ServletException"} would
	 * match {@code javax.servlet.ServletException} and its subclasses.
	 * <p><b>NB:</b> Consider carefully how specific the pattern is and whether
	 * to include package information (which isn't mandatory). For example,
	 * {@code "Exception"} will match nearly anything and will probably hide other
	 * rules. {@code "java.lang.Exception"} would be correct if {@code "Exception"}
	 * were meant to define a rule for all checked exceptions. With more unusual
	 * {@link Exception} names such as {@code "BaseBusinessException"} there is no
	 * need to use a FQN.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}.
	 * @see #rollbackFor
	 * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
	 */
	String[] rollbackForClassName() default {};

	/**
	 * Defines zero (0) or more exception {@link Class Classes}, which must be
	 * subclasses of {@link Throwable}, indicating which exception types must
	 * <b>not</b> cause a transaction rollback.
	 * <p>This is the preferred way to construct a rollback rule (in contrast
	 * to {@link #noRollbackForClassName}), matching the exception class and
	 * its subclasses.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}.
	 * @see #noRollbackForClassName
	 * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
	 */
	Class<? extends Throwable>[] noRollbackFor() default {};

	/**
	 * Defines zero (0) or more exception names (for exceptions which must be a
	 * subclass of {@link Throwable}) indicating which exception types must <b>not</b>
	 * cause a transaction rollback.
	 * <p>See the description of {@link #rollbackForClassName} for further
	 * information on how the specified names are treated.
	 * <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}.
	 * @see #noRollbackFor
	 * @see org.springframework.transaction.interceptor.DefaultTransactionAttribute#rollbackOn(Throwable)
	 */
	String[] noRollbackForClassName() default {};

}

事务的传播行为:多事务方法之间调用,事务是如何管理的

Junit用法

spring中junit4

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:xxx.xml")
public class Test05 {
}

spring中junit5

@ExtendWith(SpringExtension.class)
@ContextConfiguration("classpath:xxx.xml")
public class Test06 {
}

相当于

@SpringJUnitConfig(locations = "xxx.xml")
public class Test06 {
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/623315.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

公司测试岗来了个卷王之王,还是个00后,真让人崩溃····

现在的小年轻真的卷得过分了&#xff0c;真是完全不把自己当人啊 都说00后躺平了&#xff0c;但是有一说一&#xff0c;该卷的还是卷。这不&#xff0c;前段时间我们公司来了个00后&#xff0c;工作都没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才…

京东业务系统数据库分库分表架构设计

有幸参与了整个技术方案实施落地&#xff0c;对架构设计及技术细节深入了解&#xff0c;欢迎大家讨论交流&#xff01; 一元抢宝系统是京东虚拟新兴的一个业务系统&#xff0c;上线以来订单量一直持续增长。在距离618前两个月时&#xff0c;京东商城商品虚拟研发部对系统做了整…

SpringBoot:SpringBoot约定大于配置?②

前言&#xff1a; 这一句话&#xff0c;有些人看过就当看过了&#xff0c;对这句话的解读很多文章我是不满意的&#xff0c;里面蕴含的知识量和信息是极少人关注到的。 基于此&#xff0c;我讲两句。 一、领悟约定大于配置 字面意思&#xff1a;约定的东西要大于配置&a…

Linux中的yum

一、yum介绍 yum是一个基于RPM包(RPM是 Red-Hat Package Manager 红帽软件包管理器的缩写)构建的软件更新机制,能够自动解决软件包之间的依赖关系,解决了日常工作中的大量查找安装依赖包的时间。 二、yum仓库简介 先在yum服务器上创建yum repository(yum仓库),在仓库…

Ranger从入门到精通以及案例实操系列

1、Ranger概述 1.1、什么是Ranger Apache Ranger是一个Hadoop平台上的全方位数据安全管理框架&#xff0c;它可以为整个Hadoop生态系统提供全面的安全管理。 随着企业业务的拓展&#xff0c;企业可能在多用户环境中运行多个工作任务&#xff0c;这就需要一个可以对安全策略进…

Mysql数据库--实现主从复制搭建与同步

Mysql数据库--实现主从复制搭建与同步 &#x1f53b; 一、mysql 同步复制有关概述⛳ 前言、何为主从复制⛳ 1.1 mysql支持的复制方式⛳ 1.2 mysql支持的复制类型1.2.1&#x1f341;异步复制1.2.2&#x1f341;同步复制1.2.3&#x1f341;半同步复制1.2.4&#x1f341;[图解]-异…

Spring高手之路2——深入理解注解驱动配置与XML配置的融合与区别

文章目录 1. 配置类的编写与Bean的注册2. 注解驱动IOC的依赖注入与XML依赖注入对比3. Spring中组件的概念4. 组件注册5. 组件扫描5.1 使用ComponentScan的组件扫描5.2 xml中启用component-scan组件扫描5.3 不使用ComponentScan的组件扫描 6. 组件注册的其他注解7. 将注解驱动的…

MySQL 5.7 主从集群搭建

IP功能Linux版本192.168.56.136MasterCentOS 7.9192.168.56.140SlaveCentOS 7.9 一、安装前的准备 1、卸载老版本 &#xff08;1&#xff09;查看是否安装mariadb&#xff08;centos7默认安装&#xff09; 命令&#xff1a; rpm -qa | grep mariadb &#xff08;2&#xff…

嵌入式软件工程师培训:提升技能、实现卓越

如果您对嵌入式培训感兴趣&#xff0c;以下是一些建议和关键点&#xff0c;可以帮助您进行嵌入式培训&#xff1a; 培训目标&#xff1a;明确确定您的嵌入式培训目标。是为了提升员工的技能水平&#xff0c;使他们能够承担更高级别的嵌入式开发工作&#xff0c;还是为了向非嵌入…

16、DMA直接存储区访问

0x01、DMA简介 DMA(Direct Memory Access)一直接存储器存取&#xff0c;是单片机的一个外设&#xff0c;它的主要功能是用来搬数据&#xff0c;但是不需要占用 CPU&#xff0c;即在传输数据的时候&#xff0c;CPU 可以于其他的事情&#xff0c;好像是多线程一样数据传输支持从…

2022 中国开源创新大赛,时序数据库 TDengine 榜上有名

近日&#xff0c;2022 中国互联网发展创新与投资大赛暨 2022 年中国开源创新大赛在北京落下帷幕&#xff0c;本次大赛由中央网信办信息化发展局指导&#xff0c;中国互联网发展基金会、中国网络空间研究院、中国互联网投资基金联合主办。非常荣幸的是&#xff0c;凭借着强大的开…

他们用卫星,让中国量子通信领跑全球

光子盒研究院 上周二&#xff08;5月30日&#xff09;&#xff0c;中国宣布其神舟十六号飞船与天宫三号空间站成功对接&#xff0c;官方媒体称景海鹏、朱杨柱和桂海潮这三名中国宇航员将有机会研究“新的量子现象”。这意味着中国量子技术发展的一大突破&#xff1a;我们现在可…

IVD体外诊断已经发展成为医疗健康市场活跃领域之一

体外诊断领域的布局覆盖免疫诊断、血液诊断、尿液诊断、生化诊断、微生物诊断等。得益于自主研发驱动下的技术积累和产品创新 近年来&#xff0c;体外诊断已经发展成为医疗健康市场最活跃、增长最快的领域之一。 从全球体外诊断发展来看&#xff0c;据Kalorama Information的统…

接口测试 —— Requests库介绍

1、Requests库 Requests库是用Python语言编写&#xff0c;基于urllib3模块&#xff0c;采用Apache2 Licensed开源协议的 HTTP 库。 虽然Python的标准库中urllib3模块已经包含了平常我们使用的大多数功能&#xff0c;但是它的 API使用起来让人感觉不太友好。而Requests库使用的…

Vue+springboot果蔬有机蔬菜商城销售种植系统与设计

对于网站的前台设计&#xff0c;要保证主界面的整洁有序&#xff0c;能够抓住人的眼球&#xff0c;不会产生视觉疲劳&#xff0c;更重要的是&#xff0c;带给人容易操作的直观感受&#xff0c;这样才能留住用户去进行使用&#xff0c;增加三分热度的延续期。在系统的后台设计上…

2023预备金九银十,400道阿里必问软件测试高频面试考点详细解析

前言 临近秋招&#xff0c;又到了“金九银十”面试求职高峰期&#xff0c;在金九银十时也参与过不少面试&#xff0c;2023都说工作不好找&#xff0c;也是对开发人员的要求变高。前段时间自己有整理了一些软件测试面试常问的高频考点问题做成一份PDF文档&#xff08;400道高频…

东软、联影、科曼在今届CMEF好猛, “挖挖”背后的共同点

走出三年疫情阴霾&#xff0c;医疗行业迎来爆发式的展会营销盛况。5月14-17日&#xff0c;为期4天的第87届中国国际医疗器械博览会&#xff08;CMEF&#xff09;在上海圆满落幕&#xff01; 在这场32万平方米的全球医疗产业“航母级”盛会中&#xff0c;一众行业大咖、来自120…

优思学院|如何通过实验设计改善产品质量?

你的企业是否经常因为产品和服务不符合客户的期望而感到苦恼&#xff1f;你是否在想有没有一种方法可以在任何时候都可以帮助你解决问题&#xff1f; 那么&#xff0c;您需要一种突破性改进工具&#xff0c;它也是六西格玛项目中的”杀手锏"&#xff0c;它称为实验设计&a…

玩转学生信息管理系统——【c++】

设计一个管理系统实现对学生的基本信息&#xff08;至少包括姓名、学号、性别、出生日期、宿舍号年龄&#xff08;通过计算得到&#xff09;的管理&#xff1b;&#xff09;&#xff0c;具有数据的录入、显示、保存、查询&#xff08;按学号查查询或姓名查询&#xff09;、修改…

ASP.NET State Service服务无法启动解决方案

客户服务器ASP.NET State Service启动不起来&#xff0c;如下图所示&#xff1a; 在服务中右击属性查看基本信息&#xff0c;发现aspnet_state.exe在目录中不存在&#xff0c;如下图所示&#xff1a; 若想正常启动&#xff0c;需要重新指向有exe的目录中去&#xff0c;解决方案…