从JDK动态代理看Spring之AOP实现

本文深入浅出地介绍了Spring框架中AOP(面向切面编程)的基本概念及其与传统面向对象编程的区别,并通过JDK动态代理的示例展示了AOP的具体实现过程。

 

  Spring 缺省使用J2SE 动态代理(dynamic proxies 来作为AOP 的代理。这样任何接口都可以被代理。

Spring 也支持使用CGLIB 代理. 对于需要代理类而不是代理接口的时候CGLIB 代理是很有必要的。 如果一个业务对象并没有实现一个接口,默认就会使用CGLIB------- 这是Spring Framework 开发手册中对AOP 的一个简要概括

  其实个人看来 Spring Framework 是个大杂烩,它提供了许多框架的接口。当然它自己也有一套 MVC 框架。其中最为常见也最为重要也就是 IoC AOP 。所谓的 LightWeight Container( 轻量级 ) 就是整个容器的倾入性极低或者没有倾入性让对象与对象之间的关系通过配置来体现避免了对象之间的直接调用 ( 当然这不是轻量级容器的完全定义 ), 轻量级带来的就是单例和工厂的有效减少。嗯 …IoC 是一种思想,它的实现有依赖注入和依赖查找。开发中遇到比较多的就是依赖注入 Spring 所提供的方法有 (Setter 方法注入,构造器注入 以及接口注入 ) 三种方法的使用程度也如我所列的顺序一样,当然各人所好不同。

  AOP 就是面向切面编程,平时我们所面对的都是 OO 那是一个纵向的编程思想,而 AOP 的出现使得面向的切面 ( 即横向编程 ) 的理念得到了众多的认可。其实 AOP 的思想早期在 EJB( 个人对 EJB 了解不是很够,这里就不在细说 ) 中也得以体现,最为常用的就是声明式事务的使用。 For Example :比如我声明这个类中所有以 save 开头的接口都用事务,所以当其被调用时开启事务,成功后提交事务,失败了就回滚事务。那 Spring 中所提供的 AOPEJB 中的所采用的拦截机制有什么区别呢?对早期的 EJB(3.0 之前 ) 来说,你只有实现了 EJB 才有该功能而 Spring 则不同, Spring 对普通的 POJO 都可以实现 AOP 。这就是为什么 EJB2.x 以失败而告终,所以当 EJB3.0 卷土重来时它就加入对 Spring 的集成。这也是开源的一大优势呐。

  一下说的有点多了,吐出来的知识点可能也多了点。还是回归主题吧。谈谈 AOPSpring 中默认是通过 JDK 动态代理来是 AOP 。其实你要是对 JDK 动态代理理解烂熟于心我想我下面的内容你是不用看了。如果你还是不怎么熟悉,希望大家一起学习。我把自己学习 AOP 的心得写一写,以示例为主便于理解,讲的不好还希望大家指点指点 …..

  JDK 动态代理分静态代理和动态代理,其中静态代理适用于代理比较少的情形它是一个实实在在的代理类所以当代理比较多的时候你得去编写许多代理类效率自然就下降了。而动态是在运行时才生产的,当你调用时才生成代理当然它的前提是继承接口 (invocationHandler) 实现 invoke() 方法。下面我们看个动态代理的例子:(一个很普通的 JAVA PROJECT

               

这个 project 中,我写了:一个接口: UserManagery

接口的实现类: UserManageryImpl

代理类: SecurityHandler

以及一个简单的客户端: Client

 

 

 

 

先看接口:很普通,就是几个方法。

          

package com.jummy.spring;

public interface UserManager {
 public void  addUser(int id,String name);
 public void delUser(int id);
 public void modifyUser(int id,String name,int age);
}     

 

接着看实现类:也很普通,各个方法的具体实现。

package com.jummy.spring;

public class UsreManagerImpl implements UserManager {

	public void addUser(int id, String name) {
		/*
		 * 比如说要在添加之前做一些安全性检查,当然最原始的做法时在调用方法之前写一些验证代码。 Of
		 * course你可以将验证专门抽取出来写成一个方法甚至一个类,然后进行调用。 For example
		 * 该类中抽取出一个scurity()的方法用于验证,不过你每次验证都需要如下的调用
		 * 如此来若需要的调用的方法多了,方法甚至类就不再单一了。甚至一眼看不出这到底是一个具体功能模块
		 * 还是验证模块。这样类就不再便于管理(方法太多)。于是就出现了代理,通过代理类来实现那些不是主要的功能
		 * 这样模块的功能就很清晰,同时你在不修改原先类的情况下给该类添加功能实现
		 */
		// security();
		System.out.println("---UsreManagerImpl中的addUser方法的实现-----");
	}

	public void delUser(int id) {
		System.out.println("-----delUser方法的实现-----");
	}

	public void modifyUser(int id, String name, int age) {
		System.out.println("----modifyUser方法的实现-----");
	}

	public void security() {
		System.out.println("-----调用security方法-------");
	}
}
 

只是此时提及一下代理的作用,比如说我在调用 ADD() 方法之前需要进行安全验证(这是个很常规的步骤)传统的编码方式就是将验证方法直接写在类中,当然这无可厚非但是当需要调用的方法不断增加时整个类的就会很模糊。有人说我将需要验证的方法单独抽象出来成一个类。但这样你也要在原来的类中不断的用实例化这个验证类,这也存在所需方法不断增多的情况。这样我们就考虑 又要调用验证又要不去破坏(修改)原来类的代码。所以代理就粉墨登场,通过一个代理类来实现这个功能。

  看一下代理类:这是关键,理解这个你就理解了 AOP

package com.jummy.spring;
/*
 * 创建一个专门的执行security方法的类。实现InvocationHandler接口
 * 
 * 
 * 
 * 
 */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class SecurityHandler implements InvocationHandler {
    //适合于所有的对象
	private Object object;
	
	//通过构造方法将参数传递
	public Object newProxy(Object object){
		this.object=object;
		//生成动态代理 3个参数
		return Proxy.newProxyInstance(object.getClass().getClassLoader(),
				                      object.getClass().getInterfaces(),
				                      this);
	}
	public Object invoke(Object arg0, Method method, Object[] arg2)
			throws Throwable {
		//代理类在调用任何方法都先调用invoke()方法,这里的invoke()方法中先执行checkSecurity()方法
		checkSecurity();
		//这里可以查看invoke中调用方法的名称
		System.out.println("method name="+method.getName());
		//该参数是一个数组类型Object[] arg2
		for(int i=0;i<arg2.length;i++){
			System.out.println(arg2[i]);
		}
		Object result=null;
		//下面才是真正调用的方法,将对象添加到invoke 方法中
		try{
		result=method.invoke(object, arg2);
		//方法执行之后,也可以自定义方法
		}catch(Exception e){
			e.printStackTrace();
		}
		return result;
	}
	public void checkSecurity(){
		System.out.println("-----checkSecurity------");
	}

}
 

  下面我们来细细分析这个类,首先实现接口 invocationHandler ,还有方法 invoke(). 当代理类产生代理之后,在调用所有的方法之前都会先执行 invoke() 方法(想到 AOP 中的 BeforeAdvice 了吗?)。方法 checkSecurity() 就是我提到的验证方法,我们写在代理类中,而你在原先类中去看不到他的具体引用。其中 method.getName() 是获得所传入对象所调用的方法的方法名。 ( 假如你只需要对名称为 addUser 的方法进行单独验证,加个条件判断不就可以了麽,有点 Spring 的味道了吗? ) 再看, method.invoke() 这才是真正调用的方法,在到这一步之前我已经添加了许多验证方法了,而这在原先类中却什么都看不到一切我们都在代理类中实现的。这就避免了对原先类的修改了。当然这个方法调用之后,你还可以继续添加方法(想到了 AOPafteradvice 通知了吗?)

  当你所需要的方法不断增多是你不是可以写成 xml 文件么,通过 xml 文件来配置方法。 Spring 大致就是从这个思想演变过来的。

最后看客户端:

package com.jummy.spring;

public class Client {
  public static void main(String args[]){
	  SecurityHandler handler=new SecurityHandler();
	  UserManager userManager=(UserManager)handler.newProxy(new UsreManagerImpl());
	  userManager.addUser(19861018, "Jummy");
  }
}
 

通过代类理的实例来代理原先类( newProxy(new UserManagerImple()). 然后你再去调用 addUser() 方法。所有的验证都添加进去了。

 

  可能讲了半天有的朋友还只是说没有 AOP ,其实要讲 AOP 不一定要把 AOP 啃个遍,关键是要理解如何实现 AOP 如何区别于 OOP 的纵向编程。当然, OO 起家的我觉得 AOP 始终是个补充,万事无绝对。

 

             

 

 

 

 

内容概要:文章以“智能网页数据标注工具”为例,深入探讨了谷歌浏览器扩展在毕业设计中的实战应用。通过开发具备实体识别、情感分类等功能的浏览器扩展,学生能够融合前端开发、自然语言处理(NLP)、本地存储与模型推理等技术,实现高效的网页数据标注系统。文中详细解析了扩展的技术架构,涵盖Manifest V3配置、内容脚本与Service Worker协作、TensorFlow.js模型在浏览器端的轻量化部署与推理流程,并提供了核心代码实现,包括文本选择、标注工具栏动态生成、高亮显示及模型预测功能。同时展望了多模态标注、主动学习与边缘计算协同等未来发展方向。; 适合人群:具备前端开发基础、熟悉JavaScript和浏览器机制,有一定AI模型应用经验的计算机相关专业本科生或研究生,尤其适合将浏览器扩展与人工智能结合进行毕业设计的学生。; 使用场景及目标:①掌握浏览器扩展开发全流程,理解内容脚本、Service Worker与弹出页的通信机制;②实现在浏览器端运行轻量级AI模型(如NER、情感分析)的技术方案;③构建可用于真实场景的数据标注工具,提升标注效率并探索主动学习、协同标注等智能化功能。; 阅读建议:建议结合代码实例搭建开发环境,逐步实现标注功能并集成本地模型推理。重点关注模型轻量化、内存管理与DOM操作的稳定性,在实践中理解浏览器扩展的安全机制与性能优化策略。
基于Gin+GORM+Casbin+Vue.js的权限管理系统是一个采用前后端分离架构的企业级权限管理解决方案,专为软件工程和计算机科学专业的毕业设计项目开发。该系统基于Go语言构建后端服务,结合Vue.js前端框架,实现了完整的权限控制和管理功能,适用于各类需要精细化权限管理的应用场景。 系统后端采用Gin作为Web框架,提供高性能的HTTP服务;使用GORM作为ORM框架,简化数据库操作;集成Casbin实现灵活的权限控制模型。前端基于vue-element-admin模板开发,提供现代化的用户界面和交互体验。系统采用分层架构和模块化设计,确保代码的可维护性和可扩展性。 主要功能包括用户管理、角色管理、权限管理、菜单管理、操作日志等核心模块。用户管理模块支持用户信息的增删改查和状态管理;角色管理模块允许定义不同角色并分配相应权限;权限管理模块基于Casbin实现细粒度的访问控制;菜单管理模块动态生成前端导航菜单;操作日志模块记录系统关键操作,便于审计和追踪。 技术栈方面,后端使用Go语言开发,结合Gin、GORM、Casbin等成熟框架;前端使用Vue.js、Element UI等现代前端技术;数据库支持MySQL、PostgreSQL等主流关系型数据库;采用RESTful API设计规范,确保前后端通信的标准化。系统还应用了单例模式、工厂模式、依赖注入等设计模式,提升代码质量和可测试性。 该权限管理系统适用于企业管理系统、内部办公平台、多租户SaaS应用等需要复杂权限控制的场景。作为毕业设计项目,它提供了完整的源码和论文文档,帮助学生深入理解前后端分离架构、权限控制原理、现代Web开发技术等关键知识点。系统设计规范,代码结构清晰,注释完整,非常适合作为计算机相关专业的毕业设计参考或实际项目开发的基础框架。 资源包含完整的系统源码、数据库设计文档、部署说明和毕
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值