Spring之-AOP代码实现

一、Spring-AOP代码实现

0、引入jar包:

spring-aop.jar
spring-aspects.jar 依赖:aspectjweaver.jar
spring-expression.jar

1、定义接口

public interface OrderService {
    public void save(String name);
    public void delete(String name);
    public String query(String name);
}

2、定义接口的实现类

public class OrderServiceImpl  implements OrderService{
    @Override
    public void save(String name) {
        System.out.println("新增订单 "+ name);
    }
    @Override
    public void delete(String name) {
        System.out.println("删除订单 "+ name);

    }
    @Override
    public String query(String name) {
        System.out.println("查询订单 "+ name);
        return name;
    }
}

3、定义通知(通知其实就会额外要做的操作)

  • 前置通知
package aop.advice_pointcut;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.*;
import java.lang.reflect.Method;
/**
 * @program: SpringAll
 * @author: weidd
 * @date: 2021-04-09 23:41
 * 通知的类型
 * 前置通知     MethodBeforeAdvice
 * 后置通知     AfterReturningAdvice
 * 异常通知     ThrowsAdvice
 * 环绕通知     MethodInterceptor
 **/
public class OrderAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置通知===========");
        System.out.println("method.getName()-->"+method.getName());
    }
}

4、组件交给Spring管理同时建立组件和通知之间的关系(IOC+DI)

<?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: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
       https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--管理业务组件-->
    <bean id="orderService" class="aop.advice_pointcut.OrderServiceImpl"></bean>

    <!--配置通知类-->
    <bean id="orderAdvice" class="aop.advice_pointcut.OrderAdvice"></bean>
    
    <!--
    配置切入点(<aop:config回车引入aop的标签)
    -->
    <aop:config>
        <!--
        id:切入点在工厂中的的唯一id
        expression:表达式 execution(*[方法的返回值为任意值] 包名.类名.*[*代表所有的方法](..不关心参数)))
        -->
        <aop:pointcut id="orderPointcut" expression="execution(* aop.advice_pointcut.OrderServiceImpl.*(..))"/>
        <!--组装切面-->
        <aop:advisor advice-ref="orderAdvice" pointcut-ref="orderPointcut"></aop:advisor>
    </aop:config>
</beans>

5、测试AOP

public class Test2 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("advice/advice.xml");
        OrderService orderService = (OrderService) context.getBean("orderService");
        System.out.println("===========================");
        orderService.save("奔波儿");
        System.out.println("===========================");
        System.out.println("orderService.getClass() -->"+orderService.getClass());
/**
 * ===========================
 * 前置通知===========
 * method.getName()-->save
 * 新增订单 奔波儿
 * ===========================
 * orderService.getClass() -->class com.sun.proxy.$Proxy3
 */
    }
}

二、AOP中重要的概念:

  • Advice(通知):除目标方法以外的操作都称为通知。(额外的操作)
  • pointcut(切入点):用来告诉开发的通知类应用于项目中哪些类的哪些方法。(哪些方法需要被增强)
  • Aspect(切面):通知+切入点构成切面

AOP帮助我们解决了什么问题?

  • 通过为项目中的某些类在程序运行的过程中动态的生成代理对象,由生成的代理对象完成项目中通用的附加操作,从而减少项目中通用代码的冗余问题。

多个切面的执行顺序?

  • 切面的配置顺序就是切面的执行顺序。
  • 使用aop:advisor 中的order属性来控制切面的执行顺序。(使用order属性,配置顺序将失效。)【order是int类型的数值,数值越小越先执行】

环绕通知

  • 环绕通知注意事项:需要有一个放行的操作。并且有返回值需要处理。
package aop.advice_around;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundAdvice implements MethodInterceptor {
    //    @Override
    // jdk中动态代理: 参数1:当前代理对象. 参数2:当前执行方法对象  方法3: 参数
    // 参数:MethodInvocation :对象是spring对jdk动态代理的进一步封装.
    // MethodInvocation中包含: 当前代理对象\当前方法\目标对象\方法执行的参数
    /*public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("方法名: " + invocation.getMethod().getName());
        System.out.println("方法的参数: " + invocation.getArguments());
        System.out.println("目标对象" + invocation.getThis());
        // 放行去执行目标方法
        invocation.proceed();
        System.out.println("----目标方法执行之后----");

        return null;
    }*/
    @Override
    // jdk中动态代理: 参数1:当前代理对象. 参数2:当前执行方法对象  方法3: 参数
    // 参数:MethodInvocation :对象是spring对jdk动态代理的进一步封装.
    // MethodInvocation中包含: 当前代理对象\当前方法\目标对象\方法执行的参数
    public Object invoke(MethodInvocation invocation) throws Throwable {
//        System.out.println("方法名: " + invocation.getMethod().getName());
//        System.out.println("方法的参数: " + invocation.getArguments());
//        System.out.println("目标对象" + invocation.getThis());

        long start = System.currentTimeMillis();
        // 放行去执行目标方法
        Object proceed = invocation.proceed();// 重要 TODO

        System.out.println("----目标方法执行之后----");
        long end = System.currentTimeMillis();
        System.out.println("目标方法的执行时间为--> " + (end - start));
        return proceed;
    }
}

三、Spring 动态代理注意事项:

spring 框架生成代理的方式:
  • 两种:一种是jdk动态代理,一种是基于cglib动态代理

  • jdk proxy(默认):基于接口生成的动态代理对象,只能赋值给接口

  • Spring cglib:基于实现类生成的代理对象,技能赋值给实现类,又能赋值给接口。

  • 注意: jdk proxy : Spring AOP 基于接口生成的代理对象,只能赋值给接口,不能赋值给其实现类,否则会报错。

//spring aop基于接口生成的代理对象只赋值给接口。
EmployeeService employeeService = (EmployeeService) context.getBean("employeeService");
//将代理对象赋值给接口的实现类,程序报错。
// EmployeeServiceImpl employeeService = (EmployeeServiceImpl) context.getBean("employeeService");
  • 两种动态代理的切换:
<aop:config proxy-target-class="false">

默认是false ,jdk动态代理,基于接口实现。

四、Spring创建简单对象和复杂对象

  • 简单对象(可以通过new生成的对象):①直接将对象交个Spring容器去管理;
  • 复杂对象(不能直接new生成的对象:如抽象类和接口):①:为需要增强的组件创建一个XXXFactoryBean,实现Spring提供的FactoryBean接口,泛型为需要增强的组件。②:将该XXXFactoryBean组件交给Spring容器去管理。
  • Spring创建复杂对象代码:
public class CalendarFactory implements FactoryBean<Calendar> {
    @Override
    //用来创建复杂对象的创建方式
    public Calendar getObject() throws Exception {
        return Calendar.getInstance();
    }
    @Override
    //复杂对象的类型
    public Class<?> getObjectType() {
        return Calendar.class;
    }
    @Override
    //用来创建复杂对象的创建次数.单例
    public boolean isSingleton() {
        return true;
    }
}
<!--将复杂类的工厂类交给spring容器管理-->
<bean id="calendar" class="factoryBean.CalendarFactory"></bean>
  • Spring创建简单对象代码:
public class ProductServiceImpl implements ProductService {
    @Override
    public void save(String id) {
        System.out.println("新增商品" + id);
    }
    @Override
    public void update(String id) {
        System.out.println("更新商品");
    }
}
 <!--被代理对象 taget-->
<bean id="productService" class="aop.staticproxy.service.ProductServiceImpl"></bean>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

benboerdong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值