Spring AOP




前置增强:

使用一个程序来说明


1.定义一个服务生接口,服务生只做两件事:欢迎顾客和为顾客提供服务

public interface Waiter {
    

    void greetTo(String name);//提供服务
    void serveTo(String name);//为顾客服务
}
2.定义一个训练不足的服务生类,只是会简单向顾客打招呼,并直接提供服务,很羞涩啊

public class NaiveWaiter implements Waiter {

    public void greetTo(String name) {

        System.out.println("greet to " + name + "...");
    }

    public void serveTo(String name) {

        System.out.println("serving " + name + "...");
    }
}


3.酒店经理对此服务生不满意,对其行为进行了规范,要求在打招呼和服务之前,要对顾客使用礼貌用语:

public class GreetingBeforeAdvice implements MethodBeforeAdvice {


    public void before(Method method, Object[] args, Object object) throws Throwable {

        String clientName = (String) args[0];//顾客姓名

        System.out.println("How are you ! Mr." + clientName);//对顾客进行礼貌问候
        
    }
}
BeforeAdvice时前置增强的接口,MethodBeforeAdvice时方法前置增强的接口,是BeforeAdvice的子类 Spring目前只提供方法调用的前置增强
MethodBeforeAdvice接口只定义了唯一的方法:public void before(Method method,Object[] args,Object object) throws Throwable; method 为目标类的方法;args为目标类方法的入参;object为目标类实例。该方法发生异常时会抛出异常并阻止后面目标类方法的执行。

4.对该Naive服务生进行测试:

public class BeforeAdviceTest {

    private Waiter target;//要代理的目标
    private BeforeAdvice beforeAdvice;//前置增强
    private ProxyFactory proxyFactory;//代理工厂

    public void init(){

        target = new NaiveWaiter();//代理目标为菜鸡服务生
        beforeAdvice = new GreetingBeforeAdvice();
        proxyFactory = new ProxyFactory();

        proxyFactory.setTarget(target);//设置要代理的目标
        proxyFactory.addAdvice(beforeAdvice);//为代理目标添加增强
    }

    public void test(){

        init();
        Waiter waiterProxy = (Waiter) proxyFactory.getProxy();

        waiterProxy.greetTo("Messi");

        waiterProxy.serveTo("Ronaldo");


    }

    public static void main(String[] args) {


      new BeforeAdviceTest().test();

    }

}
运行结果为:

How are you ! Mr.Messi   -------------通过前置增强引入的礼貌用语
greet to Messi...


How are you ! Mr.Ronaldo --------------通过前置增强引入的礼貌用语
serving Ronaldo...

该服务生的服务水平得到显著提高。

通过在Spring配置文件中配置

beans.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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 代理的目标对象 -->
    <bean id="target" class="com.newsmart.advice.NaiveWaiter"/>

    <!-- 前置增强 -->
    <bean id="greetingBeforeAdvice" class="com.newsmart.advice.GreetingBeforeAdvice"/>

    <!-- 代理 -->
    <bean id="waiterProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.newsmart.advice.Waiter"
          p:interceptorNames="greetingBeforeAdvice"
          p:target-ref="target"
    />
</beans>

beans.xml配置文件说明
1.配置代理目标类
2.配置前置增强
3.配置代理:
  proxyInterfaces:配置代理目标实现的接口,多个接口使用<list>元素
  interceptorNames: 需要植入目标对象的bean列表,即前置增强
  target-ref:指定对哪个Bean进行代理,即步骤1配置的代理目标类


测试:

public class BeforeAdviceTest {

    public void test() {

        String configPath = "beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
        Waiter waiterProxy = (Waiter) applicationContext.getBean("waiterProxy");

        waiterProxy.greetTo("Messi");

        waiterProxy.serveTo("Ronaldo");


    }

    public static void main(String[] args) {


        new BeforeAdviceTest().test();

    }

}


后置增强:

经理又要求该服务生在服务完后对顾客进行礼貌问候

public class GreetingAfterAdvice implements AfterReturningAdvice {

    //在目标类方法调用后执行
    public void afterReturning(Object returnObject, Method method, Object[] args, Object object) throws Throwable {

        System.out.println("Please enjoy yourself!");
    }
}

后置增强在目标类方法调用后执行
AfterAdvice是后置增强的接口,AfterReturningAdvice接口是其子类
AfterReturningAdvice接口也只定义了唯一的方法: public void afterReturning(Object returnObject, Method method, Object[] args, Object object) throws Throwable;returnObject为目标方法返回的结果;
method为目标累的方法;args为目标类的方法的入参;object为目标类的实例。

将该后置增强添加到配置文件中:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 代理的目标对象 -->
    <bean id="target" class="com.newsmart.advice.NaiveWaiter"/>

    <!-- 前置增强 -->
    <bean id="greetingBeforeAdvice" class="com.newsmart.advice.GreetingBeforeAdvice"/>

    <!-- 后置增强 -->
    <bean id="greetingAfterAdvice" class="com.newsmart.advice.GreetingAfterAdvice"/>

    <!-- 代理 -->
    <bean id="waiterProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.newsmart.advice.Waiter"
          p:interceptorNames="greetingBeforeAdvice,greetingAfterAdvice"
          p:target-ref="target"
    />
</beans>
测试结果:

How are you ! Mr.Messi
greet to Messi...
Please enjoy yourself!


How are you ! Mr.Ronaldo

serving Ronaldo...
Please enjoy yourself!

环绕增强:

环绕增强允许在目标类方法调用前后织入横切逻辑,综合实现了前置,后置的功能

//环绕增强
public class GreetingInterceptor implements MethodInterceptor {


    //截取目标类方法的执行 并在调用前后添加横切逻辑
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {

        Object[] args = methodInvocation.getArguments(); //获取目标方法的入参
        String clientName = (String) args[0];

        System.out.println("How are you ! Mr." + clientName);//对顾客进行礼貌问候 目标方法调用前执行

        Object returnObject = methodInvocation.proceed(); //通过反射机制调用目标方法

        System.out.println("Please enjoy yourself!"); //目标方法调用后执行

        return returnObject;
    }
}


 public Object invoke(MethodInvocation methodInvocation) throws Throwable;通过methodInvocation封装目标方法,入参数组和目标实例对象。

配置文件:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 代理的目标对象 -->
    <bean id="target" class="com.newsmart.advice.NaiveWaiter"/>

    <!-- 环绕增强 -->
    <bean id="greetingAround" class="com.newsmart.advice.GreetingInterceptor"/>

    <!-- 代理 -->
    <bean id="waiterProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:proxyInterfaces="com.newsmart.advice.Waiter"
          p:interceptorNames="greetingAround"
          p:target-ref="target"
    />


</beans>

测试结果:

How are you ! Mr.Messi
greet to Messi...
Please enjoy yourself!


How are you ! Mr.Ronaldo

serving Ronaldo...
Please enjoy yourself!

与前置增强+后置增强的效果一模一样!

异常抛出增强:

异常抛出增强最适合的应用场景是事务管理。但某个事务异常时,事务管理器就必须回滚事务。

public class Service {

    public void delete(int id) {

        throw new RuntimeException("运行时异常");
    }

    public void update() throws Exception {

        // do sth

        throw new SQLException("数据更新操作异常");
    }
}
异常抛出增强:

异常抛出增强最适合的应用场景是事务管理。在某个事务异常时,事务管理器就必须回滚事务。

ThrowAdvice异常抛出增强接口没有定义任何方法,需要自行定义方法:
public void afterThrowing(Method method, Object[] args,Object target,Throwable e);
前三个入参可选,要么都有,要么都没有;最后一个必须为Throwable或其子类。

public class TransactionManager implements ThrowsAdvice {


    public void afterThrowing(Method method, Object[] args,Object target,Exception e){

        System.out.println("-----------------------");
        System.out.println("method:" + method.getName());
        System.out.println("抛出异常:" + e.getMessage());
        System.out.println("成功回滚事务");
        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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 异常抛出增强 -->
    <bean id="transactionManager" class="com.newsmart.advice.TransactionManager"/>

    <!---->
    <bean id="serviceTarget" class="com.newsmart.advice.Service"/>
    <!---->
    <bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"
          p:interceptorNames="transactionManager"
          p:target-ref="serviceTarget"
          p:proxyTargetClass="true"/>
</beans>
编写测试方法:

public class ThrowAdviceTest {

    public void test() throws Exception {
        String configPath = "beans.xml";
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(configPath);
        Service serviceProxy = (Service) applicationContext.getBean("serviceProxy");
        serviceProxy.delete(1);


    }

    public static void main(String[] args) {

        try {
            new ThrowAdviceTest().test();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}


运行结果:

-----------------------
method:delete
抛出异常:运行时异常
成功回滚事务
------------------------













【完美复现】面向配电网韧性提升的移动储能预布局与动态调度策略【IEEE33节点】(Matlab代码实现)内容概要:本文介绍了基于IEEE33节点的配电网韧性提升方法,重点研究了移动储能系统的预布局与动态调度策略。通过Matlab代码实现,提出了一种结合预配置和动态调度的两阶段优化模型,旨在应对电网故障或极端事件时快速恢复供电能力。文中采用了多种智能优化算法(如PSO、MPSO、TACPSO、SOA、GA等)进行对比分析,验证所提策略的有效性和优越性。研究不仅关注移动储能单元的初始部署位置,还深入探讨其在故障发生后的动态路径规划与电力支援过程,从而全面提升配电网的韧性水平。; 适合人群:具备电力系统基础知识和Matlab编程能力的研究生、科研人员及从事智能电网、能源系统优化等相关领域的工程技术人员。; 使用场景及目标:①用于科研复现,特别是IEEE顶刊或SCI一区论文中关于配电网韧性、应急电源调度的研究;②支撑电力系统在灾害或故障条件下的恢复力优化设计,提升实际电网应对突发事件的能力;③为移动储能系统在智能配电网中的应用提供理论依据和技术支持。; 阅读建议:建议读者结合提供的Matlab代码逐模块分析,重点关注目标函数建模、约束条件设置以及智能算法的实现细节。同时推荐参考文中提及的MPS预配置与动态调度上下两部分,系统掌握完整的技术路线,并可通过替换不同算法或测试系统进一步拓展研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值