spring aop

AOP

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。是一种通过动态代理实现程序功能扩展和统一维护的一种技术。

动态代理 原理

代理设计模式的原理:使用一个代理将原本对象包装起来,然后用该代理对象”取代”原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。类似于日志,单独独立于代码块外

举例计算机

单独一个代码 运行代码块和日志

public interface Calculator {
    int add(int a, int b);
//实现接口类
public class CalculatorImpl2 implements Calculator{
    @Override
    public int add(int a, int b) {
        //开始日志
        System.out.println("[Logging]The method add begins with ["+a+","+b+"]");
        int result = a + b;
        //返回日志
        System.out.println("[Logging]The method add returns "+result);
        return result;
    }

分离日志和代码块

  • 使用proxy类
public class LoggingProxy {
    private Object target;

    public LoggingProxy(Object target) {
        this.target = target;
    }
    public Object getProxy(){
        //类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();
      //获取被代理对象实现的接口们
       Class<?>[] interfaces = target.getClass().getInterfaces();
       //获取代理方法的对象
        Object proxy = Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
            /*
                代理对象要实现的功能的代码要写在invoke方法中
                invoke方法参数说明:
                    proxy:传入的代理对象,在inovke方法中不使用
                    method:要调用的方法
                    args:调用方法时传入的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
               	//获取方法名
                String name = method.getName();
                Object result = null;
                try {
                	//反射中的invoke方法,因为接口中方法有返回值,返回给result
                    result = method.invoke(target, args);
                    //返回日志
                    System.out.println("[★Logging]The method " + name + "returns" + result);
                } catch (Exception e) {
                	//异常日志
                    System.out.println("[★Logging]The method " + name + "occur" + e);
                }finally {
                //结束日志
                    System.out.println("[★Logging]The method "+name+" ends");
                }
                return result;

            }
        });

        return proxy;
    }
}

测试类

@Test
    public void test() {
        Calculator calculator=new CalculatorImpl();
        Calculator proxy= (Calculator) new LoggingProxy(calculator).getProxy();
        System.out.println(proxy.getClass().getName());
        int add = proxy.add(10,2);
    }
编译
com.sun.proxy.$Proxy4
[Logging]The method addreturns12
[Logging]The method add ends
12
使用spring 来操作 AOP
AOP术语
  • 横切关注点:从每个方法中抽取出来的同一类非核心业务,比如日志

  • 切面:封装横切关注点的类,每个横切面 都体现为一个通知方法。

  • 通知:切面必须要完成各个具体工作 j结束通知,异常通知,

  • 目标:被通知的对象

  • 代理:向目标对象应用通知之后创建的代理对象

  • 连接点(Joinpoint)
    横切关注点在程序代码中的具体位置 字面意思,方法执行顺序的位置,切入点需要找到连接点 插入在方法前 后 异常,结束等位置。

  • 切入点(pointcut)
    定位连接点的方式。每个类的方法中都包含多个连接点,如果把连接点看作数据库中的记录,那么切入点就是查询条件——AOP可以通过切入点定位到特定的连接点。理解为 查找的条件

Java社区里最完整最流行的AOP框架

AspectJ 通知

@Before:前置通知,在方法执行之前执行
@After:后置通知,在方法执行之后执行,不管方法是否发生异常
@AfterReturning:返回通知,在方法返回结果之后执行
@AfterThrowing:异常通知,在方法抛出异常之后执行
@Around:环绕通知,围绕着方法执行,相当于动态代理的全过程

使用基于AspectJ注解或xml配置的aop 不属于spring的。

使用注解的方式,导入俩个jar包

在这里插入图片描述
在这里插入图片描述

配置aspect.xml

扫描注解 和开启 aspectj 注解支持

<?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">
    <context:component-scan base-package="com.atguigu.spring.aop"/>
    <aop:aspectj-autoproxy/>
</beans>

注解写法

@Before(value=“execution(public int com.spring.aspectj.类名.方法(方法的类型))”
如果在一个包下,public修饰符可以用代替,全类名路径也可以用代替,方法可以特指,也可以用* 表示全部方法都使用,方法的形参类型… 表示全部,也可以特质某个类型

接口类不变
实现类
@Component("cac")
public class CalculatorImpl implements Calculator{
    @Override
    public int add(int a, int b) {
        int result = a + b;
        return result;
    }

切面类
是上文的proxy代理类中的方法执行前后异常结束的方法总类

/*此处虽然没有被getbean 但是交给asject 内部处理 类似于proxy 类处理方法好理解 
将方法返回给了 comonent,需要使用到ioc管理器,所以需要声明注解
因为aspectj 也需要交给spring ioc容器处理,所以要声明 让ioc可以处理。
*/
@Component  //切面交给spring ioc容器管理 ,
@Aspect  //声明当前类是一个切面 
public class LoggingAspectJ{
	//通过连接点找到方法使用前在方法执行之前执行
	@Before(value="execution(public int com.spring.aop.Calculator.add(int,int))")
	public void before(){
		System.out.println("在方法执行之前执行!");
	}
}

或者用around 代替全部

 @Around("execution(* Calculator.*(..))")//加工
        public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        //获取方法名
        String methodName = proceedingJoinPoint.getSignature().getName();
        //获取调用方法时传入的参数
        Object[] args = proceedingJoinPoint.getArgs();
        Object result = null;
        try {
            //前置通知
            System.out.println("[★★★Logging]The method "+methodName+" begins with "+ Arrays.toString(args));
            //将方法的调用转到原始对象上
            result = proceedingJoinPoint.proceed();
            //返回通知
            System.out.println("[★★★Logging]The method "+methodName+" returns "+result);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            //异常通知
            System.out.println("[★★★Logging]The method "+methodName+" occurs "+throwable);
        }finally {
            //后置通知
            System.out.println("[★★★Logging]The method "+methodName+" ends");
        }
        return result;
    }
测试类
public void test(){
	ApplicationContext ioc= new ClassPathXmlApplicationContext("aspectj.xml");
	Calculator cac=(Calculator) ioc.getBean("cac");
	String name=cac.getClass().getName();
	system.out.println("name");
	cac.add(6,2);
}

结果
在这里插入图片描述
cac类的名字是proxy,加入注解后, aspectj 处理计算机类传入的对象,返回了一个proxy对象,前面讲过 动态代理的介绍。

基于XML配置aop

除了使用aspectj 还可以使用spring自己的方式声明切面,xml元素完成
AspectJ更多应用

<bean class="com.spring.aop.CalculatorImpl" id="calculator"></bean>
 <bean class="com.spring.aop.LoggingAspectJ2" id="aspectJ"></bean>
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.atguigu.spring.aop.Calculator.*(..))" />
        <aop:aspect ref="aspectJ">
            <aop:before method="beforeAdvice" pointcut-ref="pointcut"></aop:before>
            <aop:after method="afterAdvice" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturning"    pointcut-ref="pointcut" returning="result"/>
            <aop:after-throwing method="afterThrowable" pointcut-ref="pointcut" throwing="e"/>
            <aop:around method="aroundAdvice" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

类中无需标注注解了
测试类

 @Test
    public void test2() {
        ApplicationContext ioc=new ClassPathXmlApplicationContext("bean-xml.xml");
        Calculator cac = (Calculator) ioc.getBean("calculator");
        cac.add(10, 2);
    }
}

结果
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值