通过例子全面解析Java中的Aop技术-包括静态代理,动态代理,Spring Aop(全面解析,附带全部源码,小白看一遍也可以理解)

AOP概述Aspect Oriented Programming

所谓AOP,就是面向方面(切面)的编程,简单来说,就是通过面向切面,在执行的方法前后加上所需要实现的事情,比如,日志,计算方法执行的时间,实现事务等。这样做的目的一方面在于不改变原有代码,提高通用性,最重要的是通过切面可以在需要的地方加上所需要做的任何事情。

我们通过最简单例子来说明

这里我们要实现在执行加减法运算的前后,分别打印出提示信息

首先定义一个加减运算的接口

package com.markorg.top.general;

/**
 * @Author Mark
 *
 * @Date 2018年6月10日
 * 
 * @Describe:定义进行计算的接口
 */
public interface ICalculate {
	
	public int plus(int x, int y);

	public int minus(int x, int y);

}

写出方法的实现

package com.markorg.top.general;

/**
 * @Author Mark
 *
 * @Date 2018年6月10日
 * 
 * @Describe:加减法的实现类
 */
public class Calculate implements ICalculate {
	/**
	 * @加法运算
	 */
	public int plus(int x, int y) {
		int m = x + y;
		System.out.println(m);
		return m;
	}

	/**
	 * @减法运算
	 */
	public int minus(int x, int y) {
		int n = x - y;
		System.out.println(n);
		return n;
	}

}

接下来实现在计算前后在控制台打印出信息

第一种方式,直接在调用方法的时候进行打印

package com.markorg.top.general;

/**
 * @Author Mark
 *
 * @Date 2018年6月10日
 * 
 * @Describe:不用切面的方法
 */
public class General {
	public static void main(String[] args) {
		ICalculate calculate = new Calculate();
		System.out.println("加法运行前");
		calculate.plus(10, 1);
		System.out.println("加法运行后");
		System.out.println("减法运行前");
		calculate.minus(20, 12);
		System.out.println("减法运行后");

	}

}

方法执行后控制台打印的结果

加法运行前
11
加法运行后
减法运行前
8
减法运行后

这种方法简单粗暴,但是每次实现的时候都要写,代码复用性差

扫描二维码关注公众号,回复: 1749114 查看本文章

第二种方式,我们使用代理模式来实现

package com.markorg.top.general;

/**
 * @Author Mark
 *
 * @Date 2018年6月10日
 * 
 * @Describe:静态代理实现
 */
public class StaticCalculateProxy implements ICalculate {

	ICalculate ica = new Calculate();

	public int plus(int x, int y) {
		System.out.println("方法执行前的切面");
		int re = ica.plus(x, y);
		System.out.println("方法执行后的切面");
		return re;
	}

	public int minus(int x, int y) {
		System.out.println("方法执行前的切面");
		int re = ica.minus(x, y);
		System.out.println("方法执行后的切面");
		return re;
	}

	public static void main(String[] args) {
		ICalculate ic = new StaticCalculateProxy();
		ic.plus(10, 2);
		ic.minus(20, 12);

	}

}

运行的结果
方法执行前的切面
12
方法执行后的切面
方法执行前的切面
8
方法执行后的切面

通过对比我们发现,使用了代理之后,它会帮我们实现切面中加入操作,每次调用加减运算的时候,我们只需要调用代理类的实现方法就可以加上切面了。

第三种方式,我们使用JDK的动态代理来实现

虽然说第二种方法相对第一种来说,提高了复用性,不用每次都去手动加入切面,但是它有个问题,每次都需要new实现类的对象,在代理方法中才调用加减运算,有时候也会不方便。


下面是动态代理的实现类
package com.markorg.top.dynamic;

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

import com.markorg.top.general.Calculate;
import com.markorg.top.general.ICalculate;

/**
 * @Author Mark
 *
 * @Date 2018年6月10日
 * 
 * @Describe:使用JDK的动态代理来实现
 */
public class DynamicCalculate implements InvocationHandler {

	Calculate c;

	/**
	 * 使用asm生产被代理代理对象
	 * 
	 * @param c
	 * @return
	 */
	public Object getProxy(Calculate c) {
		this.c = c;
		return Proxy.newProxyInstance(c.getClass().getClassLoader(), c.getClass().getInterfaces(), this);
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("-----jdk动态代理切面执行前");
		Object result = method.invoke(c, args);
		System.out.println("-----jdk动态代理切面执行后");
		return result;
	}

	public static void main(String[] args) {
		ICalculate ic = (ICalculate) new DynamicCalculate().getProxy(new Calculate());
		ic.plus(10, 8);
		ic.minus(20, 12);
	}

}



下面是执行后控制台的结果
-----jdk动态代理切面执行前
18
-----jdk动态代理切面执行后
-----jdk动态代理切面执行前
8
-----jdk动态代理切面执行后

第四种 使用cglib动态代理来实现,这个时候被代理类可以不需要实现接口,因为是通过继承的方法,当然,你想实现接口也是可以的
下面是代码
package com.markorg.top.dynamic;

import java.lang.reflect.Method;

import com.markorg.top.general.Calculate;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @Author Mark
 *
 * @Date 2018年6月10日
 * 
 * @Describe:使用cglib实现动态代理
 */
public class CglibDynamicCalculate implements MethodInterceptor {

	Object targetObject;

	/**
	 * cglib生成所需要的业务类对象,供代理来使用
	 * 
	 * @param target
	 * @return
	 */

	public Object getProxyObject(Object object) {
		this.targetObject = object;
		// 增强器,动态代码生成器
		Enhancer enhancer = new Enhancer();
		// 回调方法
		enhancer.setCallback(this);
		// 设置生成类的父类类型
		enhancer.setSuperclass(targetObject.getClass());
		// 动态生成字节码并返回代理对象
		return enhancer.create();
	}

	 // 拦截方法
		public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			// 被织入的横切内容,开始时间 before
			System.out.println("使用cglib动态切入前=====");
			// 调用方法
			Object result = methodProxy.invoke(targetObject, args);

			// 被织入的横切内容,结束时间
			System.out.println("使用cglib动态切入后=====");

			return result;
		}

	public static void main(String[] args) {
		 Calculate ic = (Calculate) new CglibDynamicCalculate().getProxyObject(new Calculate());
		 ic.plus(10, 2);
		 ic.minus(20, 12);
	}

}


下面是控制台显示的结果
使用cglib动态切入前=====
12
使用cglib动态切入后=====
使用cglib动态切入前=====
8
使用cglib动态切入后=====


未完成,待续

猜你喜欢

转载自blog.csdn.net/csgarten/article/details/80637940