Spring知识点总结(四)之SpringAOP基础 - 代理设计模式
1. 分析程序中存在的问题(高内聚,低耦合)
通过springIOC 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();
}
} }
此时可以通过代理设计模式,将这部分代码提取到代理者中,简化层中的代码。 2. 静态代理模式
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.唱歌();
}
}
静态代理设计模式特点:
优点:
结构清晰 易于理解
缺点:
如果被代理者有多个方法,则代理者也需要开发多个方法,其中往往存在大量重复代码,仍然存在代码重复。
静态代理设计模式解决了软件分层过程中 额外的功能代码侵入模块的问题,将额外的功能代码提取到了代理者中进行,但是静态代理实现的代理者中存在大量重复的代码,并没有解决代码重复问题。所以在真正开发中--包括spring的底层,基本不会使用静态代理。
3. 动态代理 - jdk内置的动态代理
在jdk中提供了动态代理实现的工具类,直接使用该工具类就可以创建出代理者,并且可以通过内置的回调函数指定代理在工作时的执行逻辑,从而实现基于jdk原生api的动态代理机制。
java.lang.reflect
类 Proxy
java.lang.Object
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
案例:
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动态代理的原理图:

java动态代理的特点:
优点:
不需要像静态代理一样被代理方法都要实现一遍,而只需要在回调函数中进行处理就可以了,重复代码只需编写一次。
缺点:
java的动态代理是通过代理者实现和被代理者相同的接口来保证两者具有相同的方法的,如果被代理者想要被代理的方法不属于任何接口,则生成的代理者自然无法具有这个方法,也就无法实现对该方法的代理。
所以java的动态代理机制是基于接口进行的,受制于要代理的方法是否有接口的支持。
4. 动态代理 - 第三方包cglib实现的动态代理
CGLIB是第三方提供的动态代理的实现工具,不管有没有接口都可以实现动态代理。
CGLIB实现动态代理的原理是 生成的动态代理是被代理者的子类,所以代理者具有和父类即被代理者 相同的方法,从而实现代理。
a. 导入CGLIB相关包
之前导入的spring包中就包含了CGLIB
spring-core-3.2.3.RELEASE.jar
b. 开发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动态代理原理图:

CGLIB动态代理的特点:
优点:无论是否有接口都可以实现动态代理,使用场景基本不受限
缺点:第三方提供的动态代理机制,不是原生的,需要导入第三方开发包才可以使用。
Spring知识点总结(四)之SpringAOP基础 - 代理设计模式的更多相关文章
- Spring知识点总结(四)之SpringAOP基础
1. Spring aop中的基本概念 • 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候.在Spring AOP中,一个连接 ...
- JAVA-Spring AOP基础 - 代理设计模式
利用IOC DI实现软件分层,虽然解决了耦合问题,但是很多地方仍然存在非该层应该实现的功能,造成了无法“高内聚”的现象,同时存在大量重复的代码,开发效率低下. @Service public clas ...
- Spring学习笔记四:SpringAOP的使用
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6776247.html 一:AOP基础概念 (1)通知(增强)Advice 通知,其实就是我们从众多类中提取出 ...
- Spring学习(四)—— java动态代理(JDK和cglib)
JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他 的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托 ...
- Spring知识点小结(四)
一.JdbcTemplate(jdbc模版--抽取的工具) web阶段DBUtils: QueryRunner runner = new QueryRunner(dataSource); ...
- spring cloud系列教程第四篇-Eureka基础知识
通过前三篇文章学习,我们搭建好了两个微服务工程.即:order80和payment8001这两个服务.有了这两个基础的框架之后,我们将要开始往里面添加东西了.还记得分布式架构的几个维度吗?我们要通过一 ...
- Spring源码系列(三)--spring-aop的基础组件、架构和使用
简介 前面已经讲完 spring-bean( 详见Spring ),这篇博客开始攻克 Spring 的另一个重要模块--spring-aop. spring-aop 可以实现动态代理(底层是使用 JD ...
- Java基础知识点(四)
前言:记录Java基础知识点,方便熟悉与掌握. 1.面向对象的"六原则一法则" “六原则一法则”:单一职责原则.开闭原则.依赖倒转原则.里氏替换原则.接口隔离原则.合成聚合复用原则 ...
- springAOP之代理模式
springAOP指的是在spring中的AOP,什么是AOP,相对于java中的面向对象(oop),在面向对象中一些公共的行为,像日志记录,权限验证等如果都使用面向对象来做,会在每个业务方法中都写上 ...
随机推荐
- View视图调用控制器方法
1.@using XXX.Controllers;//引用控制器 2. var otherController = DependencyResolver.Current.GetService<U ...
- Sql Server 锁 排它锁 更新锁 共享锁
引用别人的.有时间整体整理下. 引用地址:http://www.cnblogs.com/wenjl520/archive/2012/08/24/2654412.html 锁的概述 一. 为什么要引入锁 ...
- c# 字体库跨域解决
网上大部分的资料说的都是在apache和ng服务器的情况下解决方案,但基本的思路都是添加响应头 场景: 页面引用css文件: <link href="http://www.tuohua ...
- C#简单实现读取txt文本文件并分页存储到数组
最近做一个VR项目,需要把某个中草药的介绍信息分页显示到unity场景里然后用VR手柄切换信息. unity的脚本是c#,就先在本地写了个代码测试了一下,利用控制台测试输出,到时候拷贝函数过去再结合交 ...
- java集合框架(一):HashMap
有大半年没有写博客了,虽然一直有在看书学习,但现在回过来看读书基本都是一种知识“输入”,很多时候是水过无痕.而知识的“输出”会逼着自己去找出没有掌握或者了解不深刻的东西,你要把一个知识点表达出来,自己 ...
- mongodb 32为安装
启动命令:mongod --dbpath D:\MongoDB\data --logpath c:\MongoDB\log\mongod.log --journal 安装引擎: mongod --db ...
- CSS3媒体查询总结
1.什么是媒体查询 媒体查询可以让我们根据设备显示器的特性(如视口宽度.屏幕比例.设备方向:横向或纵向)为其设定CSS样式,媒体查询由媒体类型和一个或多个检测媒体特性的条件表达式组成.媒体查询中可用于 ...
- 原生js封装十字参考线插件(一)
需求来源: 拓扑图之机房平面图,显示机房长宽比例尺,房间内标注各种设备间距不易实现,特在机房平面图上层加一个十字参考线 横竖两条线垂直,在鼠标指针处交叉,显示鼠标指针坐标(相对机房平面图的坐标,不是相 ...
- android的MVP模式
MVP简介 相信大家对MVC都是比较熟悉了:M-Model-模型.V-View-视图.C-Controller-控制器,MVP作为MVC的演化版本,那么类似的MVP所对应的意义:M-Model-模型. ...
- SQL 出现18456
SQL Server 2008R2 18456错误解决方案 SQL Server 2008R2 18456错误解决方案 微软解释说,因密码或用户名错误而使身份验证失败并导致连接尝试被拒时,类似下面 ...