Spring( 二 ) AOP

本文详细介绍了面向切面编程(AOP)的基本概念,包括连接点、切入点、通知、目标对象、织入、代理和切面等核心术语。同时,对比了JDK动态代理和CGLIB动态代理的特点及适用场景,并探讨了传统AOP与AspectJ AOP的实现方式,涵盖了XML配置和注解编程两种方法。
摘要由CSDN通过智能技术生成

 AOP  

Aspect Oriented Programing 面向切面编程

连接点 可以被增强的方法

切入点 连接点中被选中要增强的方法

通知/增强  拦截到切入点并执行一段代码 通知有五种类型

目标对象 被代理(增强)的对象

织入 把增强应用到被代理对象 从而创建代理对象的过程

代理 被代理类被AOP增强后产生的类

切面 增强类 切入点和通知的结合 里面定义了拦截到切入点后执行的方法(通知)

 

 JDK动态代理

JDK动态代理,必须面向接口,生成代理对象 ,如果目标对象没有实现接口,无法使用JDK动态代理 !

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 对目标对象 生成Jdk动态代理 
public class JdkProxyFactory implements InvocationHandler {

	// 被代理目标对象
	private Object target;

	// 1、 构造器 ,传入目标对象
	public JdkProxyFactory(Object target) {
		this.target = target;
	}

	// 2、提供创建代理对象的方法
	public Object createProxy() {
		return Proxy.newProxyInstance(target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), this);
	}

	@Override
	// 3、编写回调函数,拦截目标对象所有方法,都会执行invoke方法
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("记录日志:" + method.getName() + "方法被执行了...");
		return method.invoke(target, args);
	}
}

Cglib动态代理

Spring AOP 优先对接口创建代理 ,对接口代理使用JDK动态代理

如果目标对象没有接口,使用cglib动态代理

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

// 工具类,对目标进行cglib代理
public class CglibProxyFactory implements MethodInterceptor {

   // 被代理目标对象
   private Object target;

   // 1、 通过构造器,传入被代理目标对象
   public CglibProxyFactory(Object target) {
      this.target = target;
   }

   // 2、 提供生成代理对象的方法
   public Object createProxy() {
      // 用于生成代理 API类
      Enhancer enhancer = new Enhancer();
      // 设置目标类,根据类生成子类代理
      enhancer.setSuperclass(target.getClass());
      // 设置回调函数
      enhancer.setCallback(this);
      // 生成代理返回
      return enhancer.create();
   }

   @Override
   // 3、 编写回调拦截函数,拦截目标对象所有方法
   public Object intercept(Object proxy, Method method, Object[] args,
         MethodProxy methodProxy) throws Throwable {
      System.out.println("记录日志:" + method.getName() + "方法被调用....");
      return methodProxy.invokeSuper(proxy, args);// 调用父类(真实对象)的方法
      // return method.invoke(target, args);
   }
}

传统的AOP

主要用于spring2.0之前 (1.2)年代,这个版本AOP编程比较复杂

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

// 自定义 环绕通知(Spring 传统AOP Advice)
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    // 拦截目标对象方法,mi用于执行目标方法
    public Object invoke(MethodInvocation invocation) throws Throwable {
        long start = System.currentTimeMillis();
        Object returnVal = invocation.proceed(); // 执行目标方法
        long end = System.currentTimeMillis();
        System.out.println("=====================================");
        System.out.println("类  :" + invocation.getThis().getClass().getSimpleName());
        System.out.println("方法:" + invocation.getMethod().getName());
        System.out.println("耗时:" + (end - start) + "毫秒!");
        System.out.println("=====================================");
        return returnVal;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.hrh"/>

    <aop:config proxy-target-class="false">
        <aop:pointcut id="myPointcut" expression="bean(*Dao)"/>
        <aop:pointcut id="myPointcut2" expression="within(com.hrh..*)"/>
        <!--<aop:pointcut id="myPointcut3" expression="execution(*com.hrh.a.UserDaoImpl.a*())"/>-->
        <aop:advisor advice-ref="myMethodInterceptor" pointcut-ref="myPointcut"/>
    </aop:config>
</beans>

切入点语法说明

4.3.1 语法一: execution(修饰符? 返回值 方法名(参数) 异常?)

execution(* *(..)) 匹配所有spring管理对象所有方法, 第一个*任意返回值 ,第二个*任意方法, .. 任意参数

execution(* cn.itcast.spring.*..*(..)) 匹配cn.itcast.spring包中所有对象所有方法

execution(* cn.itcast.spring.CustomerService.s*(..)) 匹配CustomerService中s开头方法

 

4.3.2 语法二:bean(beanName) 匹配目标Bean所有方法

bean(*Service) 匹配所有以Service结尾BeanName 的对象

 

4.3.3 语法三:within(包.*) 匹配包下所有类的所有方法

within(cn.itcast.spring..*) 匹配spring包及其子包中类所有方法

注意: 一个.代表子目录; 两个点.. 表示后代目录

AspectJ AOP切面编程(XML)

try{

    前置增强...

    // 执行目标方法

    后置增强

}catch{

    抛出增强

}finally{

    最终通知

}

 Dao和Service(被代理类)

public class AccountDao {
    public void in(String inUser, double money) {
        System.out.println(inUser + "收到 " + money );
        int j = 1/0;
    }

    public void out(String outUser, double money) {
        System.out.println(outUser + "转出 " + money);
    }
}
public class AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String outUser, String inUser, double money) {
        accountDao.in(inUser, money);

        accountDao.out(outUser, money);
    }
}

切面类

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

// 在一个切面类,可以提供多个 advice方法
public class MyAspectJ {

    // 环绕通知: 返回object
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object returnVal = null;
        try {
           // 1 开启事务
           System.out.println("================1 开启事务");
           // 2 执行一组sql语句
           returnVal = joinPoint.proceed();
           // 3.1  提交事务
           System.out.println("================3.1 提交事务");
       } catch (Exception ex) {
           ex.printStackTrace();
           // 3.2 回滚事务
            System.out.println("================3.2 回滚事务");
       } finally {
           // 4 释放资源
            System.out.println("================4 释放资源");
       }
       return returnVal;
    }


    // 前置通知
    public void before01(JoinPoint joinPoint) {
          System.out.println("--------------------- 前置通知: 开启事务 ... ..." );
    }
    // 后置增强
    public void afterRegurning(JoinPoint joinPoint, Object returnObject) {
        System.out.println("--------------------- 后置通知: 提交事务 ... ..." );
    }
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        System.out.println("--------------------- 异常通知: 回滚事务 ... ..." );
    }
    public void after(JoinPoint joinPoint) {
	System.out.println("--------------------- 最终通知: 释放资源 ... ..." );
    }

    }
}

测试类

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:beans_aspect.xml")
public class SpringTest {

    @Value("#{accountService}")
    private AccountService accountService;

    @Test
    public void demo01() {
        accountService.transfer("张三", "李四", 10000);
    }
}

XML

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
                            http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop.xsd
">
    <!--1 配置目标类-->
    <bean id="accountDao" class="cn.hrh.AccountDao"/>
     <bean id="accountService" class="cn.hrh.AccountService">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!--2 配置增强类-->
   <bean id="myAspectJ" class="cn.hrh.MyAspectJ"/>

    <!--3 配置切入点和切面-->
    <aop:config proxy-target-class="false">
        <!--3.1 ref引入通知方法所在的类-->
        <aop:aspect ref="myAspectJ">
            <!--3.2 配置六种通知类型和切入点-->
            <aop:pointcut id="myPointcut" expression="bean(*Service)"/>
             <!--环绕增强-->
            <!--<aop:around method="around" pointcut-ref="myPointcut"/>-->

            <!--前置增强-->
            <aop:before method="before01" pointcut-ref="myPointcut"/>

            <!--后置增强-->
            <aop:after-returning method="afterRegurning" pointcut-ref="myPointcut" returning="returnObject"/>

            <!--异常通知-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="ex"/>

            <!--最终通知-->
            <aop:after method="after" pointcut-ref="myPointcut" />
        </aop:aspect>
    </aop:config>
</beans>

AspectJ AOP注解编程

Dao和Service

import org.springframework.stereotype.Repository;

@Repository("accountDao")
public class AccountDao {
    public void in(String inUser, double money) {
        System.out.println(inUser + "收到 " + money );
        //int j = 1/0;
    }

    public void out(String outUser, double money) {
        System.out.println(outUser + "转出 " + money);
    }
}
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service("accountService")
public class AccountService {

    @Value("#{accountDao}")
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String outUser, String inUser, double money) {
        accountDao.in(inUser, money);

        accountDao.out(outUser, money);
    }
}

切面类



// 切面类
@Component("myAspectJ")
@Aspect
// @Aspect 说明这个类是切面类,里面包含增强方法
public class MyAspect {

    //@Pointcut("execution(* *(..))")
    @Pointcut("within(com.hrh..*)")
    private void myAspect(){}

    //@Around("bean(*Service)")
    public Object around(ProceedingJoinPoint proceedingJoinPoint){
        Object proceed=null;
        try{
            System.out.println("开启事务");

            proceed = proceedingJoinPoint.proceed();

            System.out.println("提交事务");

        }catch(Throwable e){

            System.out.println("回滚事务");

        }finally {
            System.out.println("释放资源");
        }
        return proceed;
    }

    @Before(value = "myAspect()")
    public void before(JoinPoint joinPoint){
        System.out.println("1 前置通知啊");


    }
    @AfterReturning(value = "myAspect()",returning = "returnVal")
    public void afterReturning(JoinPoint joinPoint,Object returnVal){
        System.out.println("2 后置通知啊");
    }

    @After(value = "myAspect()")
    public void after(JoinPoint joinPoint){
        System.out.println("3 最终通知啊");
    }
    @AfterThrowing(value = "myAspect()",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Throwable ex){
        System.out.println("2 异常通知啊");
    }
}

测试类

package com.hrh;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class test {

    @Autowired
    private UserService userService;

    @Test
    public void test(){

        userService.transfer("王五","赵六",88888);

    }
}

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: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 http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:component-scan base-package="com.hrh"/>
    <aop:aspectj-autoproxy proxy-target-class="false"/>

</beans>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值