JAVA-Spring AOP基础 - 代理设计模式
利用IOC DI实现软件分层,虽然解决了耦合问题,但是很多地方仍然存在非该层应该实现的功能,造成了无法“高内聚”的现象,同时存在大量重复的代码,开发效率低下。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao; @Override
public void registUser(User user) {
try {
System.out.println("校验权限。。。");
System.out.println("开启事务。。。");
System.out.println("记录日志。。。");
userDao.addUser(user);
System.out.println("提交事务。。。");
} catch (Exception e) {
System.out.println("回滚事务");
e.printStackTrace();
}
} @Override
public void upToVIP(User user) {
try {
System.out.println("校验权限。。。");
System.out.println("开启事务。。。");
System.out.println("记录日志。。。");
userDao.updateUser(user);
System.out.println("提交事务。。。");
} catch (Exception e) {
System.out.println("回滚事务");
e.printStackTrace();
}
} @Override
public void removeUser(User user) {
try {
System.out.println("校验权限。。。");
System.out.println("开启事务。。。");
System.out.println("记录日志。。。");
userDao.deleteUser(user.getId());
System.out.println("提交事务。。。");
} catch (Exception e) {
System.out.println("回滚事务");
e.printStackTrace();
}
} }
此时,可以通过代理设计模式,将这部分代码提取到代理者中,简化层中的代码。
一、静态代理模式
优点:结构清晰,便于理解
缺点:如果被代理者有多个方法,则代理者也需要开发多个方法,其中往往存在大量重复代码,仍然存在代码重复。
静态代码设计模式解决了软件分层过程中 额外的功能代码侵入模块的问题,将额外的功能代码提取到了代理者中进行,但是静态代理实现的代理者中存在大量重复代码,并没有解决代码重复问题。所以在开发中 --包括spring的底层,基本不会使用静态代理。
package cn.tedu.staticproxy;
public interface SJSkill {
public void 吃();
public void 唱歌();
} package cn.tedu.staticproxy;
public class FBB implements SJSkill{
public void 吃(){
System.out.println("fbb吃饭。。。");
}
public void 唱歌(){
System.out.println("fbb唱歌。。。");
}
} package cn.tedu.staticproxy;
public class JJRStaticProxy implements SJSkill{ private FBB fbb = new FBB();
@Override
public void 吃() {
System.out.println("权限认证:你谁啊????");
fbb.吃();
System.out.println("记录日志:等我,我记一下来访记录");
} @Override
public void 唱歌() {
System.out.println("权限认证:你谁啊????");
fbb.唱歌();
System.out.println("记录日志:等我,我记一下来访记录");
} } package cn.tedu.staticproxy;
import org.junit.Test;
public class StaticProxyTest {
@Test
public void test01(){
JJRStaticProxy jjr = new JJRStaticProxy();
jjr.吃();
jjr.唱歌();
}
}
二、动态代理-jdk内置的动态代理
在jdk提供了动态代理实现的工具类,直接使用该工具类就可以创建出代理者,并且可以通过内置的回调函数指定代理在工作时的执行逻辑,从而实现基于jdk原生api的动态代理机制。

java动态代理的特点:
优点:不需要像静态代理一样被代理方法都要实现一遍,而只需要在回调函数中进行处理就可以了,重复代码只需编写一次。
缺点:java的动态代理是通过代理者实现和被代理者相同的接口来保证两者具有相同的方法的,如果被代理者想要被代理的方法不属于任何接口,则生成的代理者自然无法具有这个方法,也就无法实现对该方法的代理。所以java的动态代理机制是基于接口进行的,受限于要代理的方法是否有接口的支持。
案例:
package cn.tedu.javaproxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import org.junit.Test; public class JavaProxyTest {
@Test
public void test01(){
//被代理者
final FBB fbb = new FBB();
//java动态代理方式 生成fbb的代理者
/**
* classLoader:用来生成代理者类的类加载器,通常可以传入被代理者类的类加载器
* interfaces: 要求生成的代理者实现的接口们,通常就是实现和被代理者相同的接口,保证具有和被代理者相同的方法
* invocationHandler: 用来设定回调函数的回调接口,使用者需要写一个类实现此接口,从而实现其中的invoke方法,
* 在其中编写代码处理代理者调用方法时的回调过程,通常在这里调用真正对象身上的方法,并且在方法之前或之后做额外操作。
*/
SJSkill proxy = (SJSkill) Proxy.newProxyInstance(FBB.class.getClassLoader(),FBB.class.getInterfaces()
,new InvocationHandler() {
@Override
/**
* proxy: 代理者
* method:当前调用的方法对象
* args:挡墙调用的方法的参数数组
*/
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
if("拍电影".equals(method.getName())){
System.out.println("不好意思,给多少钱不拍了~~");
return null;
}else{
System.out.println("检验权限。。。。");
Object returnObj = method.invoke(fbb, args);
System.out.println("记录日志。。。。");
return returnObj;
}
}
});
//从此之后,不允许直接调用被代理者身上的方法,而是要通过代理者来调用
//fbb.吃();
//fbb.唱歌();
proxy.吃();
proxy.唱歌();
proxy.拍电影();
}
}
java动态代理原理图:

三、动态代理-第三方包cglib实现的动态代理
CGLIB是第三方提供的动态代理的实现工具,不管有没有接口都可以实现动态代理。
CGLIB实现动态代理的原理:生成的动态代理是被代理者的子类,所以代理者具有和父类即被代理者相同的方法,从而实现代理。
CGLIB动态代理的特点:
优点:无论是否有接口都可以实现动态代理,使用场景基本不受限制
缺点:第三方提供的动态代理机制不是原生的,需要导入第三方的开发包才可以使用。
案例:
先导入CGLIB相关包:spring-core-3.2.3.RELEASE.jar
如果导入了spring包就包含了CGLIB
package cn.tedu.cglibproxy; import java.lang.reflect.Method; import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy; public class CglibProxyTest {
@Test
public void test01(){
final FBB fbb = new FBB();
//增强器
Enhancer enhancer = new Enhancer();
//设定接口 -- 此方法要求生成的动态代理额外实现指定接口们 ,单cglib动态代理不是靠接口实现的,所以可以不设置
enhancer.setInterfaces(fbb.getClass().getInterfaces());
//设定父类 -- 此处要传入被代理者的类,cglib是通过集成被代理者的类来持有和被代理者相同的方法的,此方法必须设置
enhancer.setSuperclass(fbb.getClass());
//设定回调函数 -- 为增强器设定回调函数,之后通过增强器生成的代理对象调用任何方法都会走到此回调函数中,实现调用真正被代理对象的方法的效果
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
if("拍电影".equals(method.getName())){
System.out.println("对不起,不拍了~~~");
return null;
}else{
System.out.println("检查权限。。。");
Object returnObj = method.invoke(fbb, args);
System.out.println("记录日志。。。");
return returnObj;
}
}
});
//生成代理对象
FBB proxy = (FBB) enhancer.create();
proxy.吃();
proxy.唱歌();
proxy.拍电影();
}
}
CGLIB动态代理原理图:
将功能代码提取到代理者中,实现 “高内聚” 的效果。
package cn.tedu.em.service; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import cn.tedu.em.dao.UserDao;
import cn.tedu.em.domain.User; @Service
public class UserServiceImpl implements UserService { @Autowired
private UserDao userDao; public void upToVIP(User user){
userDao.updateUser(user);
} public void removeUser(User user){
userDao.deleteUser(5);
} public void registUser(User user){
userDao.addUser(user);
}
} package cn.tedu.em.service; import java.lang.reflect.Method; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Service; @Service
public class UserServiceImplCglibProxy { @Autowired
@Qualifier("userServiceImpl")
private UserService userService; public UserServiceImplCglibProxy() { } public UserService getCglibProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setInterfaces(userService.getClass().getInterfaces());
enhancer.setSuperclass(userService.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy mproxy) throws Throwable {
try {
System.out.println("校验权限。。。");
System.out.println("开启事务。。。");
System.out.println("记录日志。。。"); Object returnObj = method.invoke(userService, args); System.out.println("提交事务。。。");
return returnObj;
} catch (Exception e) {
System.out.println("回滚事务");
e.printStackTrace();
throw new RuntimeException(e);
}
}
});
return (UserService) enhancer.create();
}
} package cn.tedu.em.web; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; import cn.tedu.em.domain.User;
import cn.tedu.em.service.UserServiceImplCglibProxy; @Controller
public class RegistServlet { @Autowired
//private UserService userService;
//private UserServiceImplJavaProxy proxy;
private UserServiceImplCglibProxy proxy;
public void regist(){
User user = new User(1,"LK","断桥残雪","4192@qq.com");
//proxy.getJavaProxy().upToVIP(user);
proxy.getCglibProxy().upToVIP(user);
}
}
JAVA-Spring AOP基础 - 代理设计模式的更多相关文章
- CgLib动态代理学习【Spring AOP基础之一】
如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...
- [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.
前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习 ...
- [Spring框架]Spring AOP基础入门总结一.
前言:前面已经有两篇文章讲了Spring IOC/DI 以及 使用xml和注解两种方法开发的案例, 下面就来梳理一下Spring的另一核心AOP. 一, 什么是AOP 在软件业,AOP为Aspect ...
- Java Spring AOP用法
Java Spring AOP用法 Spring AOP Java web 环境搭建 Java web 项目搭建 Java Spring IOC用法 spring提供了两个核心功能,一个是IoC(控制 ...
- 死磕Spring之AOP篇 - Spring AOP自动代理(二)筛选合适的通知器
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...
- 死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...
- 从零开始学 Java - Spring AOP 实现用户权限验证
每个项目都会有权限管理系统 无论你是一个简单的企业站,还是一个复杂到爆的平台级项目,都会涉及到用户登录.权限管理这些必不可少的业务逻辑.有人说,企业站需要什么权限管理阿?那行吧,你那可能叫静态页面,就 ...
- 从零开始学 Java - Spring AOP 实现主从读写分离
深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...
- Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式
Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式 主题 概念 Hibernate 延迟加载的代理模式 Spring AOP的代理模式 区别和联系 静态代理和动态代理 概念 代 ...
随机推荐
- LR编写Socket脚本方法2(从文件读取报文)
之前,给大家分享了LoadRunner编写socket协议脚本的基本方法与规则,今天给大家分享下,如何从本地文件,读取内容,并作为报文,发送到服务端:该方法也是在工作中遇到的一个难点,想通过这种方 ...
- Kafka —— 基于 ZooKeeper 搭建 Kafka 高可用集群
一.Zookeeper集群搭建 为保证集群高可用,Zookeeper集群的节点数最好是奇数,最少有三个节点,所以这里搭建一个三个节点的集群. 1.1 下载 & 解压 下载对应版本Zookeep ...
- Linux下Flume的安装部署
一.前置条件 Flume需要依赖JDK 1.8+,JDK安装方式见本仓库: Linux环境下JDK安装 二 .安装步骤 2.1 下载并解压 下载所需版本的Flume,这里我下载的是CDH版本的Flum ...
- node中websocket的使用
web Socket和Socket.IO框架 http协议是无状态的,就是说客户端可以给服务器提交请求,但是服务器不能向客户端提交请求,但是我们实际项目中会要求客户和服务器双方是类似电话那种关系, 一 ...
- HTML5新增的标签与属性
一.关于DTD HTML5 不基于 SGML,所以不需要引用 DTD(HTML 4.01 基于 SGML) 二.HTML5结构标签 <header> 标记定义一个页面或一个区域的头部 &l ...
- 多语言应用性能监控系统:Elastic APM
▶ 概述 Elastic APM 是基于 Elastic Stack 构建的应用性能监控系统.通过 Elastic APM 可以监控应用程序,收集有关请求的响应时间.数据库查询.高速缓存调用.外部 H ...
- C# 位运算及实例计算
前言: 平时在实际工作中很少用到这个,虽然都是一些比较基础的东西,但一旦遇到了,又不知所云.刚好最近接触了一些相关这方面的项目,所以也算是对 这些内容重新温习实践了一遍.所以这篇不仅作为个人备忘,也分 ...
- Linux嵌入式GDB调试环境搭建
======================= 我的环境 ==========================PC 端: CPU:x86_64, 系统:Ubuntu,IP:172.16.2.212开发 ...
- Python与C/C++相互调用
参考链接:https://www.cnblogs.com/yanzi-meng/p/8066944.html
- 解决thinkphp在开发环境下文件模块找不到的问题
win10系统下,phpstudy开发环境下小问题描述: 找不到public公共模块. Not Found The requested URL /public/admin/login.html was ...