利用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基础 - 代理设计模式的更多相关文章

  1. CgLib动态代理学习【Spring AOP基础之一】

    如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...

  2. [Spring框架]Spring AOP基础入门总结二:Spring基于AspectJ的AOP的开发.

    前言: 在上一篇中: [Spring框架]Spring AOP基础入门总结一. 中 我们已经知道了一个Spring AOP程序是如何开发的, 在这里呢我们将基于AspectJ来进行AOP 的总结和学习 ...

  3. [Spring框架]Spring AOP基础入门总结一.

    前言:前面已经有两篇文章讲了Spring IOC/DI 以及 使用xml和注解两种方法开发的案例, 下面就来梳理一下Spring的另一核心AOP. 一, 什么是AOP 在软件业,AOP为Aspect ...

  4. Java Spring AOP用法

    Java Spring AOP用法 Spring AOP Java web 环境搭建 Java web 项目搭建 Java Spring IOC用法 spring提供了两个核心功能,一个是IoC(控制 ...

  5. 死磕Spring之AOP篇 - Spring AOP自动代理(二)筛选合适的通知器

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  6. 死磕Spring之AOP篇 - Spring AOP自动代理(三)创建代理对象

    该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...

  7. 从零开始学 Java - Spring AOP 实现用户权限验证

    每个项目都会有权限管理系统 无论你是一个简单的企业站,还是一个复杂到爆的平台级项目,都会涉及到用户登录.权限管理这些必不可少的业务逻辑.有人说,企业站需要什么权限管理阿?那行吧,你那可能叫静态页面,就 ...

  8. 从零开始学 Java - Spring AOP 实现主从读写分离

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  9. Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式

    Hibernate 延迟加载的代理模式 和 Spring AOP的代理模式 主题 概念 Hibernate 延迟加载的代理模式 Spring AOP的代理模式 区别和联系 静态代理和动态代理 概念 代 ...

随机推荐

  1. 在C#中用静态类来扩展类的方法

    目录 在C#中用静态类来扩展类的方法 1.待扩展类 2.用于扩展的静态类中的静态方法 3 静态扩展方法的调用 4 适用场景 在C#中用静态类来扩展类的方法 1.待扩展类 private IList&l ...

  2. 安装Flume——海量日志收集聚合系统

    下载flume:  1.官方网站下载: http://flume.apache.org/download.html 2.百度网盘资源: apache-flume-1.9.0-bin.tar 链接:ht ...

  3. 【设计模式】结构型03外观模式(Facade Pattern)

    [设计模式]结构型02装饰模式(Decorator Pattern) 意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 主要解决:降低访问 ...

  4. java 中的一些运算符问题

    逻辑运算符 && 与 &: 在这二个与运算符中,一般用于if的判断中,A&&B,假设A的条件不满足时 则不会去判断后面的B, 如果A满足条件时就会接下来去做B条 ...

  5. TensorFlow 2.0 入门教程实战案例

    中文文档 TensorFlow 2 / 2.0 中文文档 知乎专栏 欢迎关注知乎专栏 https://zhuanlan.zhihu.com/geektutu 一.实战教程之强化学习 TensorFlo ...

  6. RedisCrawlSpider

    这个RedisCrawlSpider类爬虫继承了RedisCrawlSpider,能够支持分布式的抓取.因为采用的是crawlSpider,所以需要遵守Rule规则,以及callback不能写pars ...

  7. Scratch3 二次开发系列

       Scratch3.0来啦!!! Scratch做为图像化编程的首选语言,拖过积木块搭建实现动画游戏的制作.Scratch3添加了音乐.画笔.视频侦测.文字朗读.翻译等选择性下载扩展积木,可实现积 ...

  8. Java编程思想:序列化基础部分

    import java.io.*; import java.util.Date; import java.util.Random; public class Test { public static ...

  9. [算法]Python判断一个点是否在多边形内部

    题目: 代码: # -*- coding:utf-8 -*- def rayCasting(p, poly): px = p['x'] py = p['y'] flag = False i = 0 l ...

  10. 使用flink Table &Sql api来构建批量和流式应用(3)Flink Sql 使用

    从flink的官方文档,我们知道flink的编程模型分为四层,sql层是最高层的api,Table api是中间层,DataStream/DataSet Api 是核心,stateful Stream ...