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. Caffe2——C++ 预测(predict)Demo

    因为最近入坑Caffe2,它最近还一直在更新,所以坑比较多,官方也只给出了python的demo,C++的暂时还找不到,有也只有一个简单版的,不够用,所以就总结了一下,结合网上和自己的实践,整理了一下 ...

  2. JDK__下载地址

    1. http://www.oracle.com/technetwork/java/archive-139210.html ZC: 貌似 从JDK7开始,有for ARM的版本,类似 : “Linux ...

  3. POST方式跨域上传文件

    JSONP请求有限制: 第一,不能跳出两层, 第二,不支持POST. 往往解决跨域POST请求的方案是个"古老"方法, 请求同域下的iframe. 服务器端:  需要附加头信息: ...

  4. 51nod1293 dp

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1293 1293 球与切换器 题目来源: Codility 基准时间限制: ...

  5. IOS-通讯录

    一.通讯录简介 iOS提供了AddressBook.framework框架,允许开发者与设备中的通讯录进行数据交互   二.查询授权状态 可以调用ABAddressBookGetAuthorizati ...

  6. 公有云厂商DDoS防护产品竞品分析——内含CC的一些简单分析,貌似多是基于规则,CC策略细粒度ip/url//ua/refer

    公有云厂商DDoS防护产品竞品分析 from:http://www.freebuf.com/articles/network/132239.html 行文初衷 由于工作关系,最近接触了很多云上用户,对 ...

  7. is(':visible')

    .end()为结束前面处理函数,返回到最初的元素 .next()为此元素的下一个元素,可以再加上.next()表示下下一个元素,以此类推 :visible 选择器选取每个当前是可见的元素.语法:$(& ...

  8. Swagger实践和总结

    Swagger学习和实践 最近安装并使用了一下Swagger-ui.Swagger-editor和Swagger-codegen,感觉还不错. Swagger 是一个规范和完整的框架,用于生成.描述. ...

  9. 初识Linux(三)--文件系统基本结构

    Linux文件系统是一个倒立的单根树状结构,文件名称严格区分大小写(windows系统则是对大小写不明感的).路径用“/”分隔,跟windows的“\”不同. 这里我画了一张一般Linux系统的正常目 ...

  10. MySQL密码过期

    1.用mysql命令行登录mysql的root用户 2.重新修改root密码 SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpass'); my ...