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:\workspace\Wireless-Router\test-pilling\target\test-classes\methods\test==>0
ENTRY_MODIFY
[2018-11-20 12:53:18] DEBUG FileListenServiceImpl:69 - update file : E:\workspace\Wireless-Router\test-pilling\target\test-classes\methods\test==>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:\workspace\Wireless-Router\test-pilling\target\test-classes\methods\test
ENTRY_CREATE
[2018-11-20 13:05:13] DEBUG FileListenServiceImpl:62 - create file : E:\workspace\Wireless-Router\test-pilling\target\test-classes\methods\test==>0

spring切面配置,代理用jdk和cglib的区别的更多相关文章

  1. Spring的两种动态代理:Jdk和Cglib 的区别和实现

    这是有意义的一天!自己研究一路畅通的感觉真爽 原理是参考大神的,代码手敲 一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处 ...

  2. 动态代理的两种方式,以及区别(静态代理、JDK与CGLIB动态代理、AOP+IoC)

    Spring学习总结(二)——静态代理.JDK与CGLIB动态代理.AOP+IoC   目录 一.为什么需要代理模式 二.静态代理 三.动态代理,使用JDK内置的Proxy实现 四.动态代理,使用cg ...

  3. [转]java动态代理(JDK和cglib)

    转自:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html java动态代理(JDK和cglib) JAVA的动态代理 代理模式 代理 ...

  4. Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC

    一.为什么需要代理模式 假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: package com.zhangguo.Spring041.aop01; public class Mat ...

  5. Spring的两种代理JDK和CGLIB的区别浅谈

    一.原理区别: java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 而cglib动态代理是利用asm开源包,对代理对象类的class文件 ...

  6. Spring学习(四)—— java动态代理(JDK和cglib)

    JAVA的动态代理 代理模式 代理模式是常用的java设计模式,他 的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托 ...

  7. java动态代理(JDK和cglib)(转载)

    原文地址:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html 高亮部分是我的理解. JAVA的动态代理 代理模式 代理模式是常用的j ...

  8. java的静态代理和动态代理(jdk、cglib)

    一.代理模式 代理的概念来自于设计模式中的代理模式,先了解一下代理模式 1.结构图 2.参与者 Subject:接口,定义代理类和实际类的共用接口 RealSubject:实际类,实现Subject这 ...

  9. 动态代理jdk和cglib的区别

    学习来源贴:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类, ...

随机推荐

  1. spring security实现限制登录次数功能

    本节是在基于注解方式进行的,后面的例子都会基于注解形式,不再实现XML配置形式,毕竟注解才是趋势嘛! 关键在于实现自定义的UserDetailsService和AuthenticationProvid ...

  2. hibernate配置文件的详解

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE hibernate-configurati ...

  3. Linux 利用管道父子进程间传递数据

    [原文] fork()函数:用于创建子进程,子进程完全复制父进程的资源,相当于父进程的拷贝.具体理解,运用父进程的同一套代码,通过判断进程ID来执行不同进程的不同任务. 返回值正常为子进程ID,出错返 ...

  4. Pandas描述性统计

    有很多方法用来集体计算DataFrame的描述性统计信息和其他相关操作. 其中大多数是sum(),mean()等聚合函数,但其中一些,如sumsum(),产生一个相同大小的对象. 一般来说,这些方法采 ...

  5. angular指令详解--自定义指令

    自定义指令 directive()这个方法是用来定义指令的: angular.module('myApp', []) .directive('myDirective', function ($time ...

  6. mysql中开启慢查询日志

    开启慢查询日志,需要在配置文件my.ini中配置. long_query_time = 1 #设置慢查询时间,配置是下划线log-slow-queries = d:\mysql5\logs\mysql ...

  7. 条款10:让operator=返回一个reference to *this

    例如对象x,y,z.要实现连锁赋值(假设operator=已经重载过了):x = y = z,那么operator=则必须返回一个*this. 注意这个条款不仅仅适合于operator=,对于oper ...

  8. UI-UIScrollView

    - (void)viewDidLoad { [super viewDidLoad]; scrollView = [[UIScrollView alloc] initWithFrame:CGRectMa ...

  9. Android平台下渗透测试工具大集合

    Android平台下渗透测试工具大集合 分享一个google的项目,各种Android下的渗透测试工具. Ad Network Detector (1.2): http://market.androi ...

  10. jdk1.8 HashMap 实现 数组+链表/红黑树

    转载至 http://www.cnblogs.com/leesf456/p/5242233.html 一.前言 在分析jdk1.8后的HashMap源码时,发现网上好多分析都是基于之前的jdk,而Ja ...