Java动态代理学习2——静态代理和动态代理并对照spring的通知

简介:

 

一、代理模式 

代理模式是常用的java设计模式,特征是代理类委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 

按照代理的创建时期,代理类可以分为两种:

静态代理:由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。 
动态代理:在程序运行时运用反射机制动态创建而成。 

 

 

二、静态代理

public interface CountDao
{
	// 查看账户方法
	public void queryCount();

	// 修改账户方法
	public void updateCount();

}

public class CountDaoImpl implements CountDao
{
	public void queryCount()
	{
		System.out.println("查看账户方法...");
	}

	public void updateCount()
	{
		System.out.println("修改账户方法...");
	}
}

public class CountProxy implements CountDao
{
	private CountDao countDao;

	public CountProxy(CountDao countDao)
	{
		this.countDao = countDao;
	}

	@Override
	public void queryCount()
	{
		System.out.println("事务处理之前");
		countDao.queryCount();
		System.out.println("事务处理之后");
	}

	@Override
	public void updateCount()
	{
		System.out.println("事务处理之前");
		countDao.updateCount();
		System.out.println("事务处理之后");
	}
}

public class TestCount
{
	public static void main(String[] args)
	{
		CountProxy countProxy = new CountProxy(new CountDaoImpl());
		countProxy.updateCount();
		countProxy.queryCount();
	}
}

 

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 


 

三、动态代理

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

 

1 JDK动态代理

JDK动态代理中包含一个类和一个接口

 

InvocationHandler接口

public interface InvocationHandler { 
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
}  

Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject

 

Proxy类

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) throws IllegalArgumentException 

ClassLoader loader:类加载器
Class<?>[] interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类实例

public interface PersonService
{
	public void save();
}

public class PersonServiceImpl implements PersonService
{
	public void save()
	{
		System.out.println("人员增加");
	}
}

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

public class PersonProxy implements InvocationHandler
{
	// 目标对象
	private Object target;

    // 返回一个代理类对象
	public Object createProxyInstance(Object target)
	{
		this.target = target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}

	// 上述代码中调用的this就是当前代理对象,会自动调用该方法
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
	{
		Object result = null;
		System.out.println("前置通知");
		try
		{		
			result = method.invoke(target, args);
			System.out.println("后置通知");
		}
		catch(Exception e)
		{
			System.out.println("例外通知");
		}
		finally
		{
			System.out.println("最终通知"); 
		}
		return result;
	}
}

public class TestProxy
{
	public static void main(String[] args)
	{
		PersonProxy bp = new PersonProxy();
		PersonService ps = (PersonService)bp.createProxyInstance(new PersonServiceImpl());
		ps.save();
	}
}

前置通知
人员增加
后置通知
最终通知

JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。 

 

 

2 CGLIB动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承所以不能对final修饰的类进行代理。 

public interface PersonService
{
	public void save();
}

public class PersonServiceImpl implements PersonService
{
	public void save()
	{
		System.out.println("人员增加");
	}
}

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

/**
 * 使用CGLIB动态代理
 */
public class PersonProxy implements MethodInterceptor
{
	private Object target;

	// 返回一个代理类对象
	public Object createProxyInstance(Object target)
	{
		this.target = target;
		Enhancer enhancer = new Enhancer();

		// 设置目标类为父类,会覆盖目标类的非final方法
		enhancer.setSuperclass(this.target.getClass());

		// 回调方法
		enhancer.setCallback(this);

		// 创建代理对象
		return enhancer.create();
	}

	// 上述代码中调用的this就是当前代理对象,会自动调用该方法
	// 方法一
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
	{
		Object result = null;
		System.out.println("前置通知");
		try
		{
			result = method.invoke(target, args);
			System.out.println("后置通知");
		}
		catch (Exception e)
		{
			System.out.println("例外通知");
		}
		finally
		{
			System.out.println("最终通知");
		}
		return result;
	}
}

public class PersonProxy2 implements MethodInterceptor
{
	private Object target;

	// 返回一个代理类对象
	public Object createProxyInstance(Object target)
	{
		this.target = target;
		Enhancer enhancer = new Enhancer();

		// 设置目标类为父类,会覆盖目标类的非final方法
		enhancer.setSuperclass(this.target.getClass());

		// 回调方法
		enhancer.setCallback(this);

		// 创建代理对象
		return enhancer.create();
	}
	
	// 方法二
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable
	{
		Object result = null;
		System.out.println("前置通知");
		try
		{
			result = proxy.invokeSuper(obj, args);
			System.out.println("后置通知");
		}
		catch (Exception e)
		{
			System.out.println("例外通知");
		}
		finally
		{
			System.out.println("最终通知");
		}
		return result;
	}
}

public class TestProxy
{
	public static void main(String[] args)
	{
		PersonProxy cglib = new PersonProxy();
		PersonServiceClass ps1 = (PersonServiceClass) cglib.createProxyInstance(new PersonServiceClass());
		ps1.save();
		System.out.println("--------------------");
		PersonProxy2 cglib2 = new PersonProxy2();
		PersonServiceClass ps2 = (PersonServiceClass) cglib2.createProxyInstance(new PersonServiceClass());
		ps2.save();
	}
}

 

前置通知
增加人员
后置通知
最终通知
--------------------
前置通知
增加人员
后置通知
最终通知

参考并演绎自地址:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

 

目录
相关文章
|
25天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
64 2
|
12天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
28 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
1月前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
1月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
57 9
|
1月前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
21天前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
24 0
|
2月前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
95 2
|
23天前
|
Java 数据库连接 API
Spring 框架的介绍(Java EE 学习笔记02)
Spring是一个由Rod Johnson开发的轻量级Java SE/EE一站式开源框架,旨在解决Java EE应用中的多种问题。它采用非侵入式设计,通过IoC和AOP技术简化了Java应用的开发流程,降低了组件间的耦合度,支持事务管理和多种框架的无缝集成,极大提升了开发效率和代码质量。Spring 5引入了响应式编程等新特性,进一步增强了框架的功能性和灵活性。
41 0
|
1月前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
35 0