zoukankan      html  css  js  c++  java
  • spring切面配置,代理用jdk和cglib的区别

      jdk的动态代理大家应该都听说过,条件是必须要有接口;cglib不要求接口,那么它是怎么实现切面的呢?很简单,通过继承,它动态的创建出一个目标类的子类,复写父类的方法,由此实现对方法的增强。看例子:

      spring-core.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
        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/context 
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-4.0.xsd ">
        <context:annotation-config />
        <context:component-scan base-package="com.wulinfeng.test.testpilling" />
        <bean class="com.wulinfeng.test.testpilling.util.PropertiesConfigUtil">
            <property name="ignoreUnresolvablePlaceholders" value="true" />
            <property name="locations">
                <list>
                    <value>classpath:global.properties</value>
                </list>
            </property>
            <property name="fileEncoding">
                <value>UTF-8</value>
            </property>
        </bean>
    
        <bean
            class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
            <property name="staticMethod"
                value="com.wulinfeng.test.testpilling.service.TestPillingService.init" />
        </bean>
    
        <bean id="advice" class="com.wulinfeng.test.testpilling.util.TimeCostUtil" />
    
        <aop:config>
            <aop:pointcut
                expression="execution(* com.wulinfeng.*.testpilling.service..*Service.*(..))"
                id="pointCut" />
            <aop:advisor advice-ref="advice" pointcut-ref="pointCut" />
        </aop:config>
    </beans>

      通知类:

    package com.wulinfeng.test.testpilling.util;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    
    /**
     * 统计接口时延
     *
     * @author wulinfeng
     * @version C10 2018年11月19日
     * @since SDP V300R003C10
     */
    public class TimeCostUtil implements MethodInterceptor
    {
        private static Logger LOGGER = LogManager.getLogger(TimeCostUtil.class);
        
        @Override
        public Object invoke(MethodInvocation invocation)
            throws Throwable
        {
            // 获取服务开始时间
            long beginTime = System.currentTimeMillis();
            
            // 获取类名和方法名
            String srcClassName = "";
            String methodName = "";
            if (invocation != null)
            {
                String className = invocation.getClass() != null ? invocation.getClass().getName() : "";
                LOGGER.debug("The proxy class name is : " + className);
                if (invocation.getMethod() != null)
                {
                    methodName = invocation.getMethod().getName();
                }
                if (invocation.getThis() != null && invocation.getThis().getClass() != null)
                {
                    srcClassName = invocation.getThis().getClass().getName();
                    
                }
            }
            
            // 调用原来的方法
            Object result = invocation.proceed();
            
            // 打印耗时
            LOGGER.debug(srcClassName + "." + methodName + " cost time: " + (System.currentTimeMillis() - beginTime));
            
            return result;
        }
        
    }

      目标类:

    package com.wulinfeng.test.testpilling.service;
    
    import java.io.IOException;
    import java.nio.file.FileSystems;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.StandardWatchEventKinds;
    import java.nio.file.WatchEvent;
    import java.nio.file.WatchKey;
    import java.nio.file.WatchService;
    import java.util.concurrent.Executors;
    
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.springframework.stereotype.Service;
    
    /**
     * 监听文件修改,打印到日志里
     *
     * @author wulinfeng
     * @version C10 2018年11月20日
     * @since SDP V300R003C10
     */
    @Service
    public class FileListenServiceImpl implements FileListenService
    {
        private static Logger LOGGER = LogManager.getLogger(FileListenServiceImpl.class);
        
        @Override
        public void updateOnListen(String filePath)
            throws IOException
        {
            LOGGER.debug("The file path is : " + filePath);
            
            // 监听文件所在路径
            Path path = Paths.get(filePath);
            final WatchService ws = FileSystems.getDefault().newWatchService();
            path.register(ws,
                StandardWatchEventKinds.ENTRY_MODIFY,
                StandardWatchEventKinds.ENTRY_DELETE,
                StandardWatchEventKinds.ENTRY_CREATE);
            Executors.newCachedThreadPool().execute(new Runnable()
            {
                
                @Override
                public void run()
                {
                    while (true)
                    {
                        try
                        {
                            WatchKey key = ws.take();
                            for (WatchEvent<?> event : key.pollEvents())
                            {
                                System.out.println(event.kind().toString());
                                if (event.kind().equals(StandardWatchEventKinds.ENTRY_CREATE))
                                {
                                    Path createdPath = (Path)event.context();
                                    createdPath = path.resolve(createdPath);
                                    long size = Files.size(createdPath);
                                    LOGGER.debug("create file : " + createdPath + "==>" + size);
                                }
                                else if (event.kind().equals(StandardWatchEventKinds.ENTRY_MODIFY))
                                {
                                    Path createdPath = (Path)event.context();
                                    createdPath = path.resolve(createdPath);
                                    long size = Files.size(createdPath);
                                    LOGGER.debug("update file : " + createdPath + "==>" + size);
                                }
                                else if (event.kind().equals(StandardWatchEventKinds.ENTRY_DELETE))
                                {
                                    Path createdPath = (Path)event.context();
                                    createdPath = path.resolve(createdPath);
                                    LOGGER.debug("delete file : " + createdPath);
                                }
                            }
                            key.reset();
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
        
    }

      另一个TestPillingService没有实现接口,不贴了,看下单测:

    package com.wulinfeng.test.testpilling;
    
    import java.io.IOException;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.wulinfeng.test.testpilling.service.FileListenService;
    import com.wulinfeng.test.testpilling.service.TestPillingService;
    import com.wulinfeng.test.testpilling.util.PropertiesConfigUtil;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-core.xml"})
    public class TimeCostUtilTest
    {
        @Autowired
        TestPillingService tps;
        
        @Autowired
        FileListenService fls;
        @Test
        public void timeCostTest()
            throws IOException
        {
            String CLASS_PATH = TestPillingService.class.getResource("/").getPath().startsWith("/")
                ? TestPillingService.class.getResource("/").getPath().substring(1)
                : TestPillingService.class.getResource("/").getPath();
            String filePath = CLASS_PATH + PropertiesConfigUtil.getProperty("filepath", "methods");
            fls.updateOnListen(filePath);
            tps.editMethodContent("test", "hello world!");
        }
        
        
    }

      运行结果:

    log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
    log4j:WARN Please initialize the log4j system properly.
    log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
    ERROR StatusLogger Unable to locate appender "httpClient-log" for logger config "org.asynchttpclient"
    [2018-11-20 12:53:18] DEBUG TestPillingService:71 - Enter TestPillingService.init, filePath : methods, loginPath : login
    [2018-11-20 12:53:18] DEBUG TimeCostUtil:32 - The proxy class name is : org.springframework.aop.framework.ReflectiveMethodInvocation
    [2018-11-20 12:53:18] DEBUG FileListenServiceImpl:34 - The file path is : E:/workspace/Wireless-Router/test-pilling/target/test-classes/methods
    [2018-11-20 12:53:18] DEBUG TimeCostUtil:48 - com.wulinfeng.test.testpilling.service.FileListenServiceImpl.updateOnListen cost time: 6
    [2018-11-20 12:53:18] DEBUG TimeCostUtil:32 - The proxy class name is : org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation
    [2018-11-20 12:53:18] DEBUG TimeCostUtil:48 - com.wulinfeng.test.testpilling.service.TestPillingService.editMethodContent cost time: 43
    ENTRY_CREATE
    [2018-11-20 12:53:18] DEBUG FileListenServiceImpl:62 - create file : E:workspaceWireless-Router	est-pilling	arget	est-classesmethods	est==>0
    ENTRY_MODIFY
    [2018-11-20 12:53:18] DEBUG FileListenServiceImpl:69 - update file : E:workspaceWireless-Router	est-pilling	arget	est-classesmethods	est==>14

      我们看到jdk动态代理的实际实现类是ReflectiveMethodInvocation,它最终实现了MethodInterceptor接口的invoke方法和MethodInvocation接口的getMethod方法;而cglib动态代理实际实现类为CglibAopProxy的内部类CglibMethodInvocation(它继承自ReflectiveMethodInvocation,复写了invokeJoinpoint方法)。他们俩执行目标类的实际方法时都是通过ReflectiveMethodInvocation的proceed来进行的。

      如果我们把<aop:config>改成这样:

    <aop:config proxy-target-class="true">

       测试结果:

    log4j:WARN No appenders could be found for logger (org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
    log4j:WARN Please initialize the log4j system properly.
    log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
    ERROR StatusLogger Unable to locate appender "httpClient-log" for logger config "org.asynchttpclient"
    [2018-11-20 13:05:12] DEBUG TestPillingService:71 - Enter TestPillingService.init, filePath : methods, loginPath : login
    [2018-11-20 13:05:13] DEBUG TimeCostUtil:32 - The proxy class name is : org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation
    [2018-11-20 13:05:13] DEBUG FileListenServiceImpl:34 - The file path is : E:/workspace/Wireless-Router/test-pilling/target/test-classes/methods
    [2018-11-20 13:05:13] DEBUG TimeCostUtil:48 - com.wulinfeng.test.testpilling.service.FileListenServiceImpl.updateOnListen cost time: 50
    [2018-11-20 13:05:13] DEBUG TimeCostUtil:32 - The proxy class name is : org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation
    [2018-11-20 13:05:13] DEBUG TimeCostUtil:48 - com.wulinfeng.test.testpilling.service.TestPillingService.editMethodContent cost time: 42
    ENTRY_DELETE
    [2018-11-20 13:05:13] DEBUG FileListenServiceImpl:75 - delete file : E:workspaceWireless-Router	est-pilling	arget	est-classesmethods	est
    ENTRY_CREATE
    [2018-11-20 13:05:13] DEBUG FileListenServiceImpl:62 - create file : E:workspaceWireless-Router	est-pilling	arget	est-classesmethods	est==>0
  • 相关阅读:
    关于程序出现 “因为应用程序正在发送一个输入同步呼叫,所以无法执行传出的呼叫”
    循环物理依赖
    重新生成执行计划
    SQL SERVER 2008 存储过程传表参数
    关于operator void* 操作符
    关于C++编译时内链接和外链接
    低级键盘钩子,在WIN7以上版本的问题
    关于SendMessage和PostMessage的理解的例子
    一个简单代码
    GET 和 POST 比较整理
  • 原文地址:https://www.cnblogs.com/wuxun1997/p/6379720.html
Copyright © 2011-2022 走看看