学习Java框架的笔记(Spring AOP)简介、动态代理、基于代理类的AOP实现、AspectJ开发

1.Spring AOP简介

1.1 什么是AOP

  • AOP的全称是:Aspect - Oriented - Programming 即 面向切面编程(也称之为:面向方面编程)
  • 在传统的业务处理代码中,通常都会进行事物处理、日志记录等操作。如果使用传统的OOP方式(通过组合或者继承)的方式来达到代码的重用,会使同样的代码分散到各个方法中。如果想要关闭这个操作(功能),就需要对相关的所有方法进行修改,十分麻烦,增加了代码的耦合性,不灵活,不符合(高内聚低耦合的要求)。
  • 为解决这一问题,AOP思想出现,AOP采用横向抽取机制,将分散在各个方法中的代码提取出来(例如日志记录,需要在main方法的前后进行执行),然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方,这种就是采用横向抽取机制的方式。AOP是一种新的编程思想,不是OOP的替代品,它是OOP的延伸和补充。
  • 目前最流行的AOP框架有两个,Spring AOPAspectJ
    • 区别:
    • Spring AOP: 使用纯Java实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式想目标类织入增强代码(扩充的功能代码)。
    • AspectJ: 是基于Java语言的AOP框架,从Spring 2.0开始,Spring AOP 引用了对AspectJ的支持,AspectJ扩展了Java语言,提供了 一个专门的编译器,在编译时提供横向代码的织入。

1.2 AOP术语

AOP术语:包括Aspect(切面)、Joinpoint(连接点)、Pointcut(切入点)、Advice(通知/增强处理)、Target Object(目标对象)、 Proxy(代理)、Weaving(织入)

  • Aspect(切面):通常指封装的用于横向插入系统功能(事务,日志)的类。该类要被Spring容器识别为切面,需要在配置文件中通过< bean >元素指定
  • Joinpoint(连接点):在程序执行过程中的某个阶段点,实际上是对象的一个操作(例如:方法的调用或者异常的抛出)。
  • Pointcut(切入点):切面与程序流程的交叉点,即那些需要处理的连接点。在通常程序中,切入点指的是类/方法名。(连接点包涵切入点且更多)。
  • Advice(通知/增强处理):AOP框架在特定的切入点执行的增强处理,即在定义好的切入点执行的代码。
  • Target Object(目标对象):是指所有被通知的对象,也称为被增强对象。如果AOP框架采用的是动态的AOP实现,那么该对象就是一个被代理对象
  • Proxy(代理):将通知应用到目标对象之后被动态创建的对象。
  • Weaving(织入):将切面代码插入到目标对象上,从而生成代理对象的过程。

2. 动态代理

AOP中的代理就是由AOP框架动态生成的 一个对象,该对象可以作为目标对象使用。

增强方法的意思就是:调用切面类,将切面类中的方法加到目标类中,扩充其中方法数量,就是增强方法。

2.1 JDK动态代理

例图:
学习Java框架的笔记(Spring AOP)简介、动态代理、基于代理类的AOP实现、AspectJ开发_第1张图片
代码:
(1)创建一个web项目,导入Spring框架所需要的JAR包到项目的lib目录下,并发布到类路径下。
(2)在src目录下:创建一个com.itheima.jdk包,在该包下创建接口UserDao ,并在其中编写添加和删除的方法

package com.itheima.jdk;
public interface UserDao {
	public void addUser();		//添加
	public void deleteUser();		//删除
}

(3)在com.itheima.jdk包中,创建UserDao接口的实现类UserDaoImpl ,分别实现接口中的方法。

package com.itheima.jdk;

import org.springframework.stereotype.Repository;

// 目标类(被代理对象:房主)
@Repository("userDao")
public class UserDaoImpl implements UserDao {
	public void addUser() {
		System.out.println("添加用户");
	}
	public void deleteUser() {
		System.out.println("删除用户");
	}
}

(4)在src目录下,创建一个com.itheima.aspect包,并且在该包下创建切面类MyAspect ,在该类中定义一个模拟权限检查的方法,这两个方法就表示切面中的通知

package com.itheima.aspect;
//切面类:可以存在多个通知Advice(即增强的方法)
public class MyAspect {
	public void check_Permissions(){
		System.out.println("模拟检查权限...");
	}
	public void log(){
		System.out.println("模拟记录日志...");
	}
}

(5)在com.itheima.jdk包下,创建代理类JdkProxy,该类需要实现InvocationHandler接口,并编写代理方法。在代理方法中,需要通过Proxy类实现动态代理
反射:通过对象名/类名,获取class文件,获取该类的所有
通过对象: .getClass ; 通过类名: .class

package com.itheima.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.itheima.aspect.MyAspect;
/**
 * JDK代理类
 */
public class JdkProxy implements InvocationHandler{   //InvocationHandler接口实现invoke()方法
	// 声明目标类接口(房主)
	private UserDao userDao;
	// 创建代理方法
	public  Object createProxy(UserDao userDao) {
		this.userDao = userDao;
		// 1.类加载器(通过类名反射得到当前类.getClassLoader()再获取类加载器上的容器)
		ClassLoader classLoader = JdkProxy.class.getClassLoader();
		// 2.被代理对象实现的所有接口,通过userDao对象实例,通过反射getInterfaces获取该类所有方法
		Class[] clazz = userDao.getClass().getInterfaces();
		// 3.使用代理类,进行增强,返回的是代理后的对象(动态生成一个代理类,参数:一个加载器,userDao的所有方法,该类)
		return  Proxy.newProxyInstance(classLoader,clazz,this);
	}
	/*
	 * 所有动态代理类的方法调用,都会交由invoke()方法去处理
	 * 执行被代理对象中的方法的反射
	 * proxy 被代理后的对象 
	 * method 将要被执行的方法信息(反射) 
	 * args 执行方法时需要的参数,几个方法
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) 
                                                                throws Throwable {
		// 声明切面
		MyAspect myAspect = new MyAspect();
		// 前增强
		myAspect.check_Permissions();
		// 在目标类上调用方法,并传入参数
		Object obj = method.invoke(userDao, args);
		// 后增强
		myAspect.log();
		return obj;
	}
}

(6)在com.itheima.jdk包下,创建测试类JdkTest,在该类中的main方法中创建代理对象和目标对象,然后从代理对象中获取目标对象userDao增强后的对象,最后调用该对象的添加个删除方法

package com.itheima.jdk;
public class JdkTest{
	public static void main(String[] args) {
		// 创建代理对象
		JdkProxy jdkProxy = new JdkProxy();
         // 创建目标对象
		UserDao userDao= new UserDaoImpl();
		// 从代理对象中获取增强后的目标对象
		UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
		// 执行方法
		userDao1.addUser();
		userDao1.deleteUser();
	}
}

实验结果截图:
学习Java框架的笔记(Spring AOP)简介、动态代理、基于代理类的AOP实现、AspectJ开发_第2张图片

2.2 CGLIB代理

相比于JDK动态代理而言,CGLIB代理有一个最大优势是:JDK动态代理对象必须实现一个或多个接口。而CGLIB代理可以对没有接口的类进行代理。

(1)同上UserDao目标类一样:

package com.itheima.cglib;
//目标类
public class UserDao {
	public void addUser() {
		System.out.println("添加用户");
	}
	public void deleteUser() {
		System.out.println("删除用户");
	}
}

(2)在com.itheima.cglib包中,创建代理类CglibProxy ,该代理类需要实现MethodInterceptor接口,并实现接口中的intercept()方法

package com.itheima.cglib;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import com.itheima.aspect.MyAspect;
// 代理类
public class CglibProxy implements MethodInterceptor{
    // 代理方法
	public  Object createProxy(Object target) {
		// 创建一个动态类对象
		Enhancer enhancer = new Enhancer();
		// 确定需要增强的类,设置其父类
		enhancer.setSuperclass(target.getClass());
		// 添加回调函数(自己调用自己)
		enhancer.setCallback(this);    //this代表的就是代理类CglibProxy 本身
		// 返回创建的代理类
		return enhancer.create();
	}
	/**
	 * proxy CGlib根据指定父类生成的代理对象
	 * method 拦截的方法
	 * args 拦截方法的参数数组
	 * methodProxy 方法的代理对象,用于执行父类的方法 
	 */
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, 
            					 MethodProxy methodProxy) throws Throwable {
         // 创建切面类对象
		MyAspect myAspect = new MyAspect();
		// 前增强  
		myAspect.check_Permissions();
		// 目标方法执行
		Object obj = methodProxy.invokeSuper(proxy, args);
		// 后增强
		myAspect.log();	
		return obj;
	}
}

(3)在com.itheima.cglib包中,创建测试类CglibTest 。

package com.itheima.cglib;
// 测试类
public class CglibTest {
	public static void main(String[] args) {
		// 创建代理对象
		CglibProxy cglibProxy = new CglibProxy();
         	// 创建目标对象
		UserDao userDao = new UserDao();
         // 获取增强后的目标对象
		UserDao userDao1 = (UserDao)cglibProxy.createProxy(userDao);
		// 执行方法
		userDao1.addUser();
		userDao1.deleteUser();
	}
}

实验结果截图:
学习Java框架的笔记(Spring AOP)简介、动态代理、基于代理类的AOP实现、AspectJ开发_第3张图片

你可能感兴趣的:(java,JavaEE,Spring,AOP框架)