zoukankan      html  css  js  c++  java
  • 代理模式及案例

     *_* 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.

    好处:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

    代理模型的三种方式
      1. 静态代理
      2. 动态代理  
       JDK动态代理
       CGLIB动态代理

    一、静态代理

      在不修改目标对象方法的基础上,对目标对象方法进行扩展。

      

    //Service接口
    public interface UserService {
    
        void save();
    
        void delete();
    
        void update();
    
    }
    //Service实现
    public class UserServiceImpl implements UserService {
        @Override
        public void save() {
            System.out.println("新增用户");
        }
    
        @Override
        public void delete() {
            System.out.println("删除用户");
        }
    
        @Override
        public void update() {
            System.out.println("修改用户");
        }
    }
    /**
     * 静态代理类
     * 实现日志扩展功能
     *要求:
     *1)和目标(类)实现同样的接口
     *2)在静态代理类中传入目标对象实例,以便调用目标对象的方法
     *3)可以在静态代理类的方法中添加代理逻辑代码
     */
    public class LogProxy implements UserService{
    
        //接收目标对象实例
        private UserService userService;
    
        //使用构造方法传入目标对象实例
        public LogProxy(UserService userService){
            this.userService = userService;
        }
    
        @Override
        public void save() {
            System.out.println("before=====save");
            //调用目标对象的方法
            userService.save();
            System.out.println("after=====save");
        }
    
        @Override
        public void delete() {
            System.out.println("before=====save");
            //调用目标对象的方法
            userService.delete();
            System.out.println("after=====save");
        }
    
        @Override
        public void update() {
            System.out.println("before=====save");
            //调用目标对象的方法
            userService.update();
            System.out.println("after=====save");
        }
    }
     
    package com.lemon.a_staticproxy;
    
    import com.lemon.service.UserService;
    import com.lemon.service.impl.UserServiceImpl;
    
    //测试 
    public class Test {
        public static void main(String[] args) {
            //使用静态代理模式
            //1.创建目标对象
            UserService userService = new UserServiceImpl();
            //2.创建静态代理类对象
            UserService proxy = new LogProxy(userService);
            //3.调用代理类的方法
            proxy.save();
            proxy.update();
            proxy.delete();
        }
    }

    静态代理的缺点:

     1)一个静态代理类只能代理一个目标类

        2)静态代理类的每个方法都需要编写重复的代理逻辑,代码比较冗余

    二、JDK动态代理

      前提:目标对象有接口的情况

    /**
     * 用于生成JDK动态代理对象的工具类
     */
    public class LogProxy {
    
        /**
         * 生成JDK动态代理对象的方法
         *
         * 返回值:生成的JDK动态代理对象
         * 参数:target, 传入目标对象
         */
        public static Object getProxy(Object target){
            /**
             * 参数一:类加载器,JDK动态代理的底层使用类加载器来生成的一个动态类的。通常传入当前类的类加载器即可!!!(LogProxy.class.getClassLoader())
             * 参数二:目标对象的接口列表(所有接口),通常使用目标对象获取接口列表(target.getClass().getInterfaces())
             * 参数三:接口。 该用于编写  代理类的代理逻辑代码。通常我们要提供InvocationHandler接口的实现类(匿名内部类的方式提供)
             */
            return Proxy.newProxyInstance(
                    LogProxy.class.getClassLoader(),
                    target.getClass().getInterfaces(),
                    new InvocationHandler() {
    
                        /**
                         * invoke方法:用于编写 代理类的代理逻辑代码。
                         *      invoke方法在什么时候会被调用?
                         *            该方法会在调用JDK代理对象的每个方法的时候被执行!!!!!
                         *
                         * @param proxy: 生成JDK动态代理对象
                         * @param method: 目标对象的执行方法的对象
                         * @param args: 目标对象的方法参数列表
                         * @return 返回值:目标对象方法执行后的返回结果
                         * @throws Throwable
                         */
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            //获取目标对象的方法名称
                            String methodName = method.getName();
    
                            System.out.println("before======"+methodName);
    
                            //获取方法的参数列表
                           /* if(args!=null)
                            System.out.println(Arrays.asList(args));*/
    
                            //调用目标对象的方法
                            /**
                             * 参数一:执行的对象(必须传入目标对象,不能传入代理对象,否则会死循环)
                             * 参数二:方法的参数列表
                             */
                            Object result = method.invoke(target,args);
    
                            System.out.println("after======"+methodName);
    
                            return result;
                        }
                    }
            );
        }
    }

    三、CGLIB动态代理

      目标对象可有可无

    <!-- 导入spring-core(包含cglib依赖) -->
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
            </dependency>
        </dependencies>
    /**
     * 演示JDK动态代理
     */
    public class Demo {
    
        public static void main(String[] args) {
            //1.创建目标对象
            UserService userService = new UserServiceImpl();
            //2.创建静态代理类对象
            UserService proxy = (UserService) LogProxy.getProxy(userService);
            //3.调用代理类的方法
            proxy.save();
            proxy.delete();
            proxy.update();
        }
    }
    /**
     * 用于生成Cglib代理对象的工具类
     */
    public class LogProxy {
    
    
        /**
         * 生成Cglib代理对象
         * 返回值:生成的Cglib子类代理对象
         * 参数:目标对象(目标对象没有接口)
         */
        public static Object getProxy(Object target){
    
            /**
             * 方法返回值:生成的Cglib子类代理对象
             * 参数一:目标对象的类型(target.getClass()) (其实目标对象的类型就是Cglib代理对象 的  父类)
             * 参数二:MethodInterceptor接口,用于编写 代理对象的代理逻辑代码。通常提供MethodInterceptor接口的匿名内部即可
             */
            return Enhancer.create(
                    target.getClass(),
                    new MethodInterceptor() {
                        /**
                         * intercept方法:在调用代理对象的每个方法的时候会执行
                         * @param proxy: 生成的代理对象
                         * @param method: 目标对象的方法对象
                         * @param args: 目标对象的方法参数列表
                         * @param methodProxy: 代理对象的方法对象
                         * @return
                         * @throws Throwable
                         */
                        @Override
                        public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
    
                            //获取目标对象的方法名称
                            String methodName = method.getName();
    
                            System.out.println("before======"+methodName);
    
                            /**
                             * 调用目标对象的方法
                             */
                            //方式一:直接使用目标对象 调用 目标对象的方法
                            Object result = method.invoke(target,args);
                            //方式二:使用代理类(子类)调用 目标对象(父类)的方法
                            //invokeSuper: 调用父类的方法
                            //Object result = methodProxy.invokeSuper(proxy,args);
    
                            System.out.println("after====="+methodName);
    
                            return result;
                        }
                    }
            );
        }
    
    }
    /**
     * 演示CJLIB动态代理
     */
    public class Demo2 {
    
        public static void main(String[] args) {
            //1.创建目标对象
            UserService userService = new UserServiceImpl();
            //2.创建静态代理类对象
            UserService proxy = (UserService) LogProxy.getProxy(userService);
            //3.调用代理类的方法
            proxy.save();
            proxy.delete();
            proxy.update();
        }
    }

     *_* Spring aop 案例

    1 、创建service接口和实现

    public interface LemonService {
    
        void save();
        void delete();
        void update();
    
    }
    public class LemonServiceImpl implements LemonService {
        @Override
        public void save() {
            System.out.println("新增");
        }
    
        @Override
        public void delete() {
            System.out.println("删除");
        }
    
        @Override
        public void update() {
            System.out.println("修改");
        }
    }

    2、创建切面类

    /**
     * 日志切面类
     */
    public class LogAspect {
    
        /**
         * 通知方法(插入到目标方法的前面)
         */
        public void writeLog(){
            System.out.println("before=======");
        }
    
    }

    3、配置切面类

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- 1.创建目标对象 -->
        <bean id="lemonService" class="com.lemon.service.impl.LemonServiceImpl"/>
    
        <!-- 2.创建切面对象 -->
        <bean id="logAspect" class="com.lemon.log.LogAspect"/>
    
        <!-- 3.切面配置 -->
        <aop:config>
            <!-- 切面配置 = 通知(advice)+切入点(pointcut)-->
            <!--
                ref: 引用切面类对象
             -->
            <aop:aspect ref="logAspect">
                <!-- 定义切入点 -->
                <!--
                    id: 定义切入点的别名
                    expression: 切入点表达式(用于定义需要切入的方法)
                 -->
                <aop:pointcut id="pt" expression="execution(* com.lemon.service.impl.LemonServiceImpl.*(..))"/>
    
                <!-- 定义通知 -->
                <!--
                   method: 使用切面类的哪个方法作为通知方法
                   pointcut-ref: 关联切入点
                 -->
                <!-- 前置通知 -->
                <aop:before method="writeLog" pointcut-ref="pt"/>
            </aop:aspect>
        </aop:config>
    </beans>

      *_* Spring boot 自定义拦截器

    package com.example.demo.interceptor;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    public class MyInterceptor implements HandlerInterceptor{
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            System.out.println(">>>MyInterceptor1>>>>>>>在请求处理之前进行调用(Controller方法调用之前)");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            System.out.println(">>>MyInterceptor1>>>>>>>请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)");
            
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            System.out.println(">>>MyInterceptor1>>>>>>>在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
            
        }
    
    }

     package com.example.demo.configure;

    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    import com.example.demo.interceptor.MyInterceptor;
    @Configuration
    public class MyWebAppConfigurer extends WebMvcConfigurerAdapter{
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 第一个参数指定自定义拦截器
            // addPathPatterns 用于添加拦截规则
            // excludePathPatterns 用户排除拦截
            registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
         // 多个拦截器可以组成一个拦截器链
         //registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**");
            super.addInterceptors(registry);
        }
    
    }

      *_* Spring boot 自定义过滤器

    package com.example.demo.filter;
    
    import java.io.IOException;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public class MyFilter implements Filter{
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
                throws IOException, ServletException {
            long start = System.currentTimeMillis();
            filterChain.doFilter(servletRequest,servletResponse);
            System.out.println("时间间隔:"+(System.currentTimeMillis()-start));
            
        }
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
            
        }
    
    }
    package com.example.demo.configure;
    
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.example.demo.filter.MyFilter;
    @Configuration
    public class FilterConfig {
        @Bean
        public FilterRegistrationBean registFilter() {
            FilterRegistrationBean registration = new FilterRegistrationBean();
            registration.setFilter(new MyFilter());
            registration.addUrlPatterns("/*");
            registration.setName("MyFilter");
            registration.setOrder(1);
            return registration;
        }
    }
  • 相关阅读:
    php建立多层目录的函数
    PHP获取远程图片并调整图像大小(转)
    敏捷开发之每日站立会议
    没有所谓的人脉,只有更强的自己
    Linux上使用程序相对路径访问文件【转】
    视频图像处理基础知识1(双线性插值算法描述及实现)【转】
    视频图像处理基础知识4(视频分辨率参考 行频 隔行扫描 逐行扫描)【转】
    IPC网络高清摄像机基础知识4(Sensor信号输出YUV、RGB、RAW DATA、JPEG 4种方式区别) 【转】
    视频图像处理基础知识5(RGB与Ycbcr相互转换公式 )【转】
    视频图像处理基础知识0(双线性插值算法进行图像缩放)【转】
  • 原文地址:https://www.cnblogs.com/hnzkljq/p/12009882.html
Copyright © 2011-2022 走看看