Spring-AOP学习

Spring-AOP学习

通过java的代理模式将系统性的服务和业务代码剥离,对特定的代码进行增强处理

java代理

代理模式是一种设计模式,通过代理访问目标对象并执行相应的方法,可以在目标对象实现的基础上,增加额外的功能动作,实现功能的增强

静态代理

例如有一个IUserDao的接口,并且拥有Save()方法,并且有一个UserDao的类实现了这个接口

public interface IUserDao {
    void save();
}

public class UserDao implements IUserDao{
    @Override
    public void save() {
        System.out.println("-----已经保存数据!!!------");
    }
}

而我们需要在save中添加上事务的操作时,就可以增加一个代理,在代理中开关事务,而实际的对数据的操作委托给UserDao

public class UserDaoProxy implements IUserDao{
    private IUserDao target;
    public UserDaoProxy(IUserDao target) {
        this.target = target;
    }
    @Override
    public void save() {
        System.out.println("开始事务...");
        target.save();          // 执行目标对象的方法
        System.out.println("提交事务...");
    }
}
// 使用
public class Main {
  public static void main(String args[]){
    IUserDao target = new UserDao();
    IUserDao executor = new UserDaoProxy(target);
    target.save();
  }
}

动态代理

然而,大量使用静态代理还是需要很多冗余的代码,因此java中的proxy包支持基于反射实现动态代理机制,优点如下:

  • 不用实现目标接口的方法
  • 动态地在内存中构建代理对象
基于proxy的动态代理
public class ProxyFactory{
//维护一个目标对象
	private Object target;
	public ProxyFactory(Object target){
  	  this.target=target;
	}
//给目标对象生成代理对象
	public Object getProxyInstance(){
  	  return Proxy.newProxyInstance(
          	 target.getClass().getClassLoader(),
           	 target.getClass().getInterfaces(),
           	 new InvocationHandler() {
            	    @Override
            	    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              	      System.out.println("开始事务2");
               	     //执行目标对象方法
              	      Object returnValue = method.invoke(target, args);
               	     System.out.println("提交事务2");
               	     return returnValue;
            	    }
         	   }
 	   );
	}
}
public class App {
public static void main(String[] args) {
    IUserDao target = new UserDao();
    IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
    proxy.save();
  }
}

使用proxy代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理

基于cglib的动态代理

通过构建目标对象子类的方式实现代理,并不需要增强的方法需要实现某个特定的接口

  • 它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
  • 底层是通过使用字节码处理框架ASM来转换字节码并生成新的子类
  • 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法
public class ProxyFactory implements MethodInterceptor{
     //维护目标对象
    private Object target;
    public ProxyFactory(Object target) {
        this.target = target;
    }
   //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
       //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("开始事务...");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("提交事务...");
        return returnValue;
    }
}
public class App {
    @Test
    public void test(){
        //目标对象
        UserDao target = new UserDao();
        //代理对象
        UserDao proxy = (UserDao)new ProxyFactory(target).getProxyInstance();
        //执行代理对象的方法
        proxy.save();
    }
}

使用cglib的动态代理方式不再需要代理的方法必须实现某个接口,实际的作用相当于再内存中创建了一个增强的子类,并拦截目标对象的方法,增强后被调用

Spring-AOP

概念介绍

AOP 实际上是由目标类的代理类实现的。AOP 代理其实是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用,在java中有两种实现的方式:

  • Spring 默认使用 Java 动态代理来创建 AOP 代理, 这样就可以为任何接口实例创建代理了。
  • 当需要代理的类不是代理接口的时候, Spring 自动会切换为使用 CGLIB 代理,也可强制使用 CGLIB

在使用的时候,我们只需要关注以下三点内容:

  • 定义普通业务组件。
  • 定义切入点,一个切入点可能横切多个业务组件。
  • 定义增强处理,增强处理就是在 AOP 框架为普通业务组件织入的处理动作。

使用示例

注解模式

在配置文件中启用注解模式开关,在配置文件中新增以下内容:

 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

定义一个切面,里面包含对于切入点的一系列操作,包括Before,After,AfterReturing,AfterThroughing,Around

  1. 对于切面首先使用@Aspect注解定义切面
  2. 可以使用@Pointcut定义切入点,之后的注解可以使用切入点的函数来代替
  3. 针对切入点的不同的操作,使用注解定义不同的增强函数,也可以不需要定义切入点,直接定义各阶段拦截器
@Component
@Aspect
public class AOP {
    @Pointcut("execution(* org.example.Dao.*(..))")
    public void aop(){
    }
    //里面的值为切入点表达式
//    @Before("execution(* org.example.Dao.*(..))")
//    public void begin() {
//        System.out.println("开始事务");
//    }
//
//
//    @After("execution(* org.example.Dao.*(..))")
//    public void close() {
//        System.out.println("关闭事务");
//    }
    @Before("aop()")
    public void begin() {
        System.out.println("start transaction");
    }
    @After("aop()")
    public void close(){
        System.out.println("end transaction");
    }
}

语法解析

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
符号解析
  • ? 表示0或1,可以不写
  • '*'表示任意的类型,0 或多
  • 方法的参数为…表示为可变参数
参数解析
  • modifiers-pattern?【修饰的类型,可以不写】
  • ret-type-pattern【方法返回值类型,必写】
  • declaring-type-pattern?【方法声明的类型,可以不写】
  • name-pattern(param-pattern)【要匹配的名称,括号里面是方法的参数】
  • throws-pattern?【方法抛出的异常类型,可以不写】
示例
execution(public * *(..))

执行public修饰的,任意返回值,任意方法名的函数

execution(* set*(..))

执行任意返回值,以set命名开头的方法

execution(* com.xyz.service.AccountService.*(..))

执行任意返回值的,com.xyz.service.AccountService类下的任意方法名,任意返回值的函数

execution(* com.xyz.service.*.*(..))

执行com.xyz.service包下任意方法名,任意返回值的函数

execution(* com.xyz.service..*.*(..))

执行com.xyz.service的任意子包所有方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值