国际会议短文<fastgraphical abstractt>是什么概念

ffmpeg在iOS的使用-iFrameExtractor源码解析 - IOS - 伯乐在线
& ffmpeg在iOS的使用-iFrameExtractor源码解析
iFrameExtractor地址:
ffmpeg的简介
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。
“FFmpeg”这个单词中的”FF”指的是”Fast Forward”。
ffmpeg支持的格式
GXF, General eXchange Format, SMPTE 360M
ISO base media file format(包括QuickTime, 3GP和MP4)
Matroska(包括WebM)
MPEG program stream
MPEG transport stream(including AVCHD)
MXF, Material eXchange Format, SMPTE 377M
MSN Webcam stream
ffmpeg支持的协议
IETF标准:TCP, UDP, Gopher, HTTP, RTP, RTSP和SDP
苹果公司的相关标准:HTTP Live Streaming
RealMedia的相关标准:RealMedia RTSP/RDT
Adobe的相关标准:RTMP, RTMPT(由librtmp实现),RTMPE(由librtmp实现),RTMPTE(由librtmp)和RTMPS(由librtmp实现)
微软的相关标准:MMS在TCP上和MMS在HTTP上
iFrameExtractor的使用
Objective-C
self.video = [[VideoFrameExtractor alloc] initWithVideo:[Utilities bundlePath:@"sophie.mov"]];
video.outputWidth = 426;
video.outputHeight = 320;
self.video = [[VideoFrameExtractor alloc] initWithVideo:[Utilities bundlePath:@"sophie.mov"]];&&&&&video.outputWidth = 426;&&&&video.outputHeight = 320;
Objective-C
[video seekTime:0.0];
[NSTimer scheduledTimerWithTimeInterval:1.0/30
target:self
selector:@selector(displayNextFrame:)
userInfo:nil
repeats:YES];
[video seekTime:0.0];&&&&[NSTimer scheduledTimerWithTimeInterval:1.0/30&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& target:self&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& selector:@selector(displayNextFrame:)&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& userInfo:nil&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&repeats:YES];
Objective-C
-(void)displayNextFrame:(NSTimer *)timer {
if (![video stepFrame]) {
imageView.image = video.currentI
-(void)displayNextFrame:(NSTimer *)timer {&&&&if (![video stepFrame]) {&&&&&&&&&return;&&&&}&&&&imageView.image = video.currentImage;&}
VideoFrameExtractor类解析
initWithVideo:(NSString *)moviePath方法
VideoFrameExtractor的初始化,主要是配置三个全局的结构体变量。
AVFormatContext类型的pFormatCtx,AVFormatContext主要存储视音频封装格式中包含的信息;AVInputFormat存储输入视音频使用的封装格式。每种视音频封装格式都对应一个AVInputFormat 结构。
AVCodecContext类型的pCodecCtx ,每个AVStream存储一个视频/音频流的相关数据;每个AVStream对应一个AVCodecContext,存储该视频/音频流使用解码方式的相关数据;每个AVCodecContext中对应一个AVCodec,包含该视频/音频对应的解码器。每种解码器都对应一个AVCodec结构。
AVFrame类型的pFrame,视频的话,每个结构一般是存一帧,音频可能有好几帧。解码前数据是AVPacket,解码后数据是AVFrame。
FMPEG中结构体很多。最关键的结构体他们之间的对应关系如下所示:
下面就是初始化的代码
Objective-C
-(id)initWithVideo:(NSString *)moviePath {
if (!(self=[super init]))
// Register all formats and codecs
avcodec_register_all();
av_register_all();
// Open video file
if(avformat_open_input(&pFormatCtx, [moviePath cStringUsingEncoding:NSASCIIStringEncoding], NULL, NULL) != 0) {
av_log(NULL, AV_LOG_ERROR, "Couldn't open file\n");
goto initE
// Retrieve stream information
if(avformat_find_stream_info(pFormatCtx,NULL) & 0) {
av_log(NULL, AV_LOG_ERROR, "Couldn't find stream information\n");
goto initE
// Find the first video stream
if ((videoStream =
av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0)) & 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");
goto initE
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx-&streams[videoStream]-&
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx-&codec_id);
if(pCodec == NULL) {
av_log(NULL, AV_LOG_ERROR, "Unsupported codec!\n");
goto initE
// Open codec
if(avcodec_open2(pCodecCtx, pCodec, NULL) & 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");
goto initE
// Allocate video frame
pFrame = avcodec_alloc_frame();
outputWidth = pCodecCtx-&
self.outputHeight = pCodecCtx-&
initError:
[self release];
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
-(id)initWithVideo:(NSString *)moviePath {&&&&if (!(self=[super init])) return nil;&&&&&AVCodec&&&&&&&& *pCodec;&&&&&// Register all formats and codecs&&&&avcodec_register_all();&&&&av_register_all();&&&&&// Open video file&&&&if(avformat_open_input(&pFormatCtx, [moviePath cStringUsingEncoding:NSASCIIStringEncoding], NULL, NULL) != 0) {&&&&&&&&av_log(NULL, AV_LOG_ERROR, "Couldn't open file\n");&&&&&&&&goto initError;&&&&}&&&&&// Retrieve stream information&&&&if(avformat_find_stream_info(pFormatCtx,NULL) < 0) {&&&&&&&&av_log(NULL, AV_LOG_ERROR, "Couldn't find stream information\n");&&&&&&&&goto initError;&&&&}&&&&&// Find the first video stream&&&&if ((videoStream =&&av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &pCodec, 0)) < 0) {&&&&&&&&av_log(NULL, AV_LOG_ERROR, "Cannot find a video stream in the input file\n");&&&&&&&&goto initError;&&&&}&&&&&// Get a pointer to the codec context for the video stream&&&&pCodecCtx = pFormatCtx->streams[videoStream]->codec;&&&&&// Find the decoder for the video stream&&&&pCodec = avcodec_find_decoder(pCodecCtx->codec_id);&&&&if(pCodec == NULL) {&&&&&&&&av_log(NULL, AV_LOG_ERROR, "Unsupported codec!\n");&&&&&&&&goto initError;&&&&}&&&&&// Open codec&&&&if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {&&&&&&&&av_log(NULL, AV_LOG_ERROR, "Cannot open video decoder\n");&&&&&&&&goto initError;&&&&}&&&&&// Allocate video frame&&&&pFrame = avcodec_alloc_frame();&&&&&outputWidth = pCodecCtx->width;&&&&self.outputHeight = pCodecCtx->height;&&&&&return self;&initError:&&&&[self release];&&&&return nil;}
sourceWidth和sourceHeight方法
获取屏幕的宽和高
Objective-C
-(int)sourceWidth {
return pCodecCtx-&
-(int)sourceHeight {
return pCodecCtx-&
-(int)sourceWidth {&&&&return pCodecCtx-&width;}&-(int)sourceHeight {&&&&return pCodecCtx-&height;}
setupScaler方法
设置视频播放视图的尺寸
Objective-C
-(void)setupScaler {
// Release old picture and scaler
avpicture_free(&picture);
sws_freeContext(img_convert_ctx);
// Allocate RGB picture
avpicture_alloc(&picture, PIX_FMT_RGB24, outputWidth, outputHeight);
// Setup scaler
static int sws_flags =
SWS_FAST_BILINEAR;
img_convert_ctx = sws_getContext(pCodecCtx-&width,
pCodecCtx-&height,
pCodecCtx-&pix_fmt,
outputWidth,
outputHeight,
PIX_FMT_RGB24,
sws_flags, NULL, NULL, NULL);
1234567891011121314151617181920
-(void)setupScaler {&&&&&// Release old picture and scaler&&&&avpicture_free(&picture);&&&&sws_freeContext(img_convert_ctx);&& &&&&&// Allocate RGB picture&&&&avpicture_alloc(&picture, PIX_FMT_RGB24, outputWidth, outputHeight);&&&&&// Setup scaler&&&&static int sws_flags =&&SWS_FAST_BILINEAR;&&&&img_convert_ctx = sws_getContext(pCodecCtx-&width, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& pCodecCtx-&height,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& pCodecCtx-&pix_fmt,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& outputWidth, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& outputHeight,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& PIX_FMT_RGB24,&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& sws_flags, NULL, NULL, NULL);&}
duration方法
获取音视频文件的总时间
Objective-C
-(double)duration {
return (double)pFormatCtx-&duration / AV_TIME_BASE;
-(double)duration {&&&&return (double)pFormatCtx-&duration / AV_TIME_BASE;}
currentTime方法
显示音视频当前播放的时间
Objective-C
-(double)currentTime {
AVRational timeBase = pFormatCtx-&streams[videoStream]-&time_
return packet.pts * (double)timeBase.num / timeBase.
-(double)currentTime {&&&&AVRational timeBase = pFormatCtx-&streams[videoStream]-&time_base;&&&&return packet.pts * (double)timeBase.num / timeBase.den;}
seekTime:(double)seconds方法
直接跳到音视频的第seconds秒进行播放,默认从第0.0秒开始
Objective-C
-(void)seekTime:(double)seconds {
AVRational timeBase = pFormatCtx-&streams[videoStream]-&time_
int64_t targetFrame = (int64_t)((double)timeBase.den / timeBase.num * seconds);
avformat_seek_file(pFormatCtx, videoStream, targetFrame, targetFrame, targetFrame, AVSEEK_FLAG_FRAME);
avcodec_flush_buffers(pCodecCtx);
-(void)seekTime:(double)seconds {&&&&AVRational timeBase = pFormatCtx-&streams[videoStream]-&time_base;&&&&int64_t targetFrame = (int64_t)((double)timeBase.den / timeBase.num * seconds);&&&&avformat_seek_file(pFormatCtx, videoStream, targetFrame, targetFrame, targetFrame, AVSEEK_FLAG_FRAME);&&&&avcodec_flush_buffers(pCodecCtx);}
stepFrame方法
解码视频得到帧
Objective-C
-(BOOL)stepFrame {
int frameFinished=0;
while(!frameFinished && av_read_frame(pFormatCtx, &packet)&=0) {
// Is this a packet from the video stream?
if(packet.stream_index==videoStream) {
// Decode video frame
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
return frameFinished!=0;
1234567891011121314
-(BOOL)stepFrame {&&&&// AVP&&&&int frameFinished=0;&&&&&while(!frameFinished && av_read_frame(pFormatCtx, &packet)&=0) {&&&&&&&&// Is this a packet from the video stream?&&&&&&&&if(packet.stream_index==videoStream) {&&&&&&&&&&&&// Decode video frame&&&&&&&&&&&&avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);&&&&&&&&}&&&&&}&&&&return frameFinished!=0;}
currentImage方法
获取当前的UIImage对象,以呈现当前播放的画面
Objective-C
-(UIImage *)currentImage {
if (!pFrame-&data[0])
[self convertFrameToRGB];
return [self imageFromAVPicture:picture width:outputWidth height:outputHeight];
-(UIImage *)currentImage {&&&&if (!pFrame-&data[0]) return nil;&&&&[self convertFrameToRGB];&&&&return [self imageFromAVPicture:picture width:outputWidth height:outputHeight];}
convertFrameToRGB
转换音视频帧到RGB
Objective-C
-(void)convertFrameToRGB {
sws_scale (img_convert_ctx, pFrame-&data, pFrame-&linesize,
0, pCodecCtx-&height,
picture.data, picture.linesize);
-(void)convertFrameToRGB {&&&&&&sws_scale (img_convert_ctx, pFrame-&data, pFrame-&linesize,&&&&&&&&&&&&&& 0, pCodecCtx-&height,&&&&&&&&&&&&&& picture.data, picture.linesize); }
(UIImage *)imageFromAVPicture:(AVPicture)pict width:(int)width height:(int)height方法
把AVPicture转换成UIImage把音视频画面显示出来
Objective-C
-(UIImage *)imageFromAVPicture:(AVPicture)pict width:(int)width height:(int)height {
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderD
CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pict.data[0], pict.linesize[0]*height,kCFAllocatorNull);
CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef cgImage = CGImageCreate(width,
pict.linesize[0],
colorSpace,
bitmapInfo,
kCGRenderingIntentDefault);
CGColorSpaceRelease(colorSpace);
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CGDataProviderRelease(provider);
CFRelease(data);
123456789101112131415161718192021222324
-(UIImage *)imageFromAVPicture:(AVPicture)pict width:(int)width height:(int)height {&&&&CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;&&&&CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, pict.data[0], pict.linesize[0]*height,kCFAllocatorNull);&&&&CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);&&&&CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();&&&&CGImageRef cgImage = CGImageCreate(width, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& height, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 8, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 24, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& pict.linesize[0], &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& colorSpace, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& bitmapInfo, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& provider, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& NULL, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& NO, &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& kCGRenderingIntentDefault);&&&&CGColorSpaceRelease(colorSpace);&&&&UIImage *image = [UIImage imageWithCGImage:cgImage];&&&&CGImageRelease(cgImage);&&&&CGDataProviderRelease(provider);&&&&CFRelease(data);&&&&&return image;}
: 这是我用ffmpeg写的iOS万能播放器。
:包括AVFrame、AVFormatContext、AVCodecContext、AVIOContext、AVCodec、AVStream、AVPacket
可能感兴趣的话题
o 104 回复
关于iOS频道
iOS频道分享iOS和Swift开发,应用设计和推广,iOS相关的行业动态。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2018 伯乐在线对不起,您要访问的页面暂时没有找到,您可以:博客分类:
相关性能测试和使用例子,可以参见另一篇文章:
前段时间在工作中,包括一些代码阅读过程中,spring aop经常性的会看到cglib中的相关内容,包括BeanCopier,BulkBean,Enancher等内容,以前虽大致知道一些内容,原理是通过bytecode,但没具体深入代码研究,只知其所用不知其所以然,所以就特地花了半天多的工作时间研究了CGLIB的相关源码,同时结合看了下 spring Aop中对CGLIB的使用。
本文主要通过对cglib有原理的分析,反编译查看源码,例子等方式做一个介绍。
cglib基本信息
cglib的官方网站:
cglib目前的最新版本应该是2.2,公司普遍使用的版本也是这个
官网的samples :
cglib代码包结构
core (核心代码)
ReflectUtils
KeyFactory
ClassEmitter/CodeEmitter
NamingPolicy/DefaultNamingPolicy
GeneratorStrategy/DefaultGeneratorStrategy
DebuggingClassWriter
ClassGenerator/AbstractClassGenerator
beans (bean操作类)
BeanCopier
ImmutableBean
BeanGenerator
CallbackGenerator
MethodInterceptor , Dispatcher, LazyLoader , ProxyRefDispatcher , NoOp , FixedValue , InvocationHandler(提供和jdk proxy的功能)
CallbackFilter
StringSwitcher
ParallelSorter
core核心代码部分
重要的工具类,主要封装了一些操作bytecode的基本函数,比如生成一个null_constructor,添加类属性add_property等
ReflectUtils
处理jdk reflect的工具类,比如获取一个类所有的Method,获取构造函数信息等。
ClassEmitter/CodeEmitter
对asm的classAdapter和MethodAdapter的实现,贯穿于cglib代码的处理
KeyFactory
类库中重要的唯一标识生成器,用于cglib做cache时做map key,比较底层的基础类。例子:
interface BulkBeanKey {
public Object newInstance(String target, String[] getters, String[] setters, String[] types);
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class).newInstance(targetClassName, getters, setters, typeClassNames);
每个Key接口,都必须提供newInstance方法,但具体的参数可以随意定义,通过newInstance返回的为一个唯一标示,只有当传入的所有参数的equals都返回true时,生成的key才是相同的,这就相当于多key的概念。
NamingPolicy
默认的实现类:DefaultNamingPolicy, 具体cglib动态生成类的命名控制。一般的命名规则:
被代理class name + "$$" + 使用cglib处理的class name + "ByCGLIB" + "$$" + key的hashcode
示例:FastSource$$FastClassByCGLIB$$e1a36bab.class
GeneratorStrategy
默认的实现类: DefaultGeneratorStrategy控制ClassGenerator生成class的byte数据,中间可插入自己的处理。注意这里依赖了:DebuggingClassWriter进行class generator的处理
DebuggingClassWriter
cglib封装asm的处理类,用于生成class的byte流,通过GeneratorStrategy回调ClassGenerator.generateClass(DebuggingClassWriter),将自定义的class byte处理回调给具体的cglib上层操作类,比如由具体的BeanCopier去控制bytecode的生成。
ClassGenerator
其中一个抽象实现:AbstractClassGenerator。cglib代码中核心的Class bytecode操作主体,包含了一些cache,调用NamingPolicy,GeneratorStrategy进行处理,可以说是一个最核心的调度者。
对应的类图:
外部的BeanCopier都包含了一Generator,继承自AbstractClassGenerator,实现了generateClass(ClassVisitor v),Object firstInstance(Class type)方法。
AbstractClassGenerator自身会根据Source进行cache,所以针对已经生成过的class,这里KeyFactory对应的值要相等,则会直接返回cache中的结果。所以BeanCopier每次create慢只是每次都需要new两个对象,一个是KeyFactory.newInstance,另一个是firstInstance方法调用生成一个对象。
反编译tips
大家都知道cglib是进行bytecode操作,会动态生成class,最快最直接的学习就是结合他生成的class,对照代码进行学习,效果会好很多。
system.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "指定输出目录"); 
可参见 cores/DebuggingClassWriter代码。说明:这样cglib会将动态生成的每个class都输出到文件中,然后我们可以通过decomp进行反编译查看源码。
beans (相关操作类)
BeanCopier
简单的示例代码就不做介绍,相信大家都指导怎么用,这里主要介绍下Convert的使用。
许多网友都做过BeanCopier,BeanUtils的测试,基本BeanCopier的性能是BeanUtils的10倍以上。,出了反射这一性能差异外,BeanUtils默认是开启Converter功能,允许同名,不同类型的属性进行拷贝,比如Date对象到String属性。
有兴趣的同学可以去比较下PropertyUtils,默认不开启Converter功能,发现性能是BeanUtils的2倍多。
初始化例子:BeanCopier copier = BeanCopier.create(Source.class, Target.class, true); 第三个参数useConverter,是否开启Convert,默认BeanCopier只会做同名,同类型属性的copier,否则就会报错。
public class BeanCopierTest {
public static void main(String args[]) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/tmp/1");
BeanCopier copier = BeanCopier.create(Source.class, Target.class, true);
Source from = new Source();
from.setValue(1);
Target to = new Target();
Converter converter = new BigIntConverter();
copier.copy(from, to, converter); //使用converter类
System.out.println(to.getValue());
class BigIntConverter implements net.sf.cglib.core.Converter {
public Object convert(Object value, Class target, Object context) {
System.out.println(value.getClass() + " " + value); // from类中的value对象
System.out.println(target); // to类中的定义的参数对象
System.out.println(context.getClass() + " " + context); // String对象,具体的方法名
if (target.isAssignableFrom(BigInteger.class)) {
return new BigInteger(value.toString());
反编译后看的代码:
public class Target$$BeanCopierByCGLIB$$e1c34377 extends BeanCopier
public void copy(Object obj, Object obj1, Converter converter)
Target target = (Target)obj1;
Source source = (Source)
// 注意是直接调用,没有通过reflect
target.setValue((BigInteger)converter.convert(new Integer(source.getValue()), CGLIB$load_class$java$2Emath$2EBigInteger, "setValue"));
避免每次进行BeanCopier.create创建对象,一般建议是通过static BeanCopier copier = BeanCopier.create()
合理使用converter。
应用场景:两个对象之间同名同属性的数据拷贝, 不能单独针对其中的几个属性单独拷贝
相比于BeanCopier,BulkBean将整个Copy的动作拆分为getPropertyValues,setPropertyValues的两个方法,允许自定义处理的属性。
public class BulkBeanTest {
public static void main(String args[]) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/home/ljh/cglib");
String[] getter = new String[] { "getValue" };
String[] setter = new String[] { "setValue" };
Class[] clazzs = new Class[] { int.class };
BulkBean bean = BulkBean.create(BulkSource.class, getter, setter, clazzs);
BulkSource obj = new BulkSource();
obj.setValue(1);
Object[] objs = bean.getPropertyValues(obj);
for (Object tmp : objs) {
System.out.println(tmp);
class BulkSource {
// 反编译后的代码: 
public void getPropertyValues(Object obj, Object aobj[])
BulkSource bulksource = (BulkSource)
aobj[0] = new Integer(bulksource.getValue());
避免每次进行BulkBean.create创建对象,一般建议是通过static BulkBean.create copier = BulkBean.create
应用场景:针对特定属性的get,set操作,一般适用通过xml配置注入和注出的属性,运行时才确定处理的Source,Target类,只需关注属性名即可。
相比于BeanCopier,BulkBean,都是针对两个Pojo Bean进行处理,那如果对象一个是Pojo Bean和Map对象之间,那就得看看BeanMap,将一个java bean允许通过map的api进行调用。几个支持的操作接口:
Object get(Object key)
Object put(Object key, Object value)
void putAll(Map t)
Set entrySet()
Collection values()
boolean containsKey(Object key)
public class BeanMapTest {
public static void main(String args[]) {
BeanMap map = BeanMap.create(new Pojo());
Pojo pojo = new Pojo();
pojo.setIntValue(1);
pojo.setBigInteger(new BigInteger("2"));
map.setBean(pojo);
System.out.println(map.get("intValue"));
System.out.println(map.keySet());
System.out.println(map.values());
class Pojo {
private int
private BigInteger bigI
//反编译代码查看:
//首先保存了所有的属性到一个set中
private static FixedKeySet keys = new FixedKeySet(new String[] {
"bigInteger", "intValue"
public Object get(Object obj, Object obj1)
String s = (String)obj1;
s.hashCode();
JVM INSTR lookupswitch 2: default 72
goto _L1 _L2 _L3
"bigInteger";
 //属性判断是否相等
JVM INSTR ifeq 73;
goto _L4 _L5
break MISSING_BLOCK_LABEL_73;
getBigInteger();
避免每次进行BeanMap map = BeanMap.create();创建对象,不同于BeanCopier对象,BeanMap主要针对对象实例进行处理,所以一般建议是map.setBean(pojo);进行动态替换持有的对象实例。
应用场景:针对put,putAll操作会直接修改pojo对象里的属性,所以可以通过beanMap.putAll(map)进行map&-&pojo属性的拷贝。
BeanGenerator
暂时没有想到合适的使用场景,不过BeanGenerator使用概念是很简单的,就是将一个Map&String,Class&properties的属性定义,动态生成一个pojo bean类。
BeanGenerator generator = new BeanGenerator();
generator.addProperty("intValue", int.class);
generator.addProperty("integer", Integer.class);
generator.addProperty("properties", Properties.class);
Class clazz = (Class) generator.createClass();
Object obj = generator.create();
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(obj.getClass());
for (PropertyDescriptor getter : getters) {
Method write = getter.getWriteMethod();
System.out.println(write.getName());
ImmutableBean
bean Immutable模式的一种动态class实现,Immutable模式主要应用于服务设计上,返回的pojo bean对象,不运行进行write方法调用。
说明个人是不太建议使用cglib动态class的方式来实现bean Immutable的模式,Immutable模式应该是一种服务接口上的显示声明,而不是如此隐晦,而且pojo bean尽量做到是轻量级,简答的set/get方法,如果要做充血的领域模型那就另当别论了。
reflect (class,method处理)
顾明思义,FastClass就是对Class对象进行特定的处理,比如通过数组保存method引用,因此FastClass引出了一个index下标的新概念,比如getIndex(String name, Class[] parameterTypes)就是以前的获取method的方法。通过数组存储method,constructor等class信息,从而将原先的反射调用,转化为class.index的直接调用,从而体现所谓的FastClass。
public class FastClassTest {
public static void main(String args[]) throws Exception {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/home/ljh/cglib");
FastClass clazz = FastClass.create(FastSource.class);
// fast class反射调用
FastSource obj = (FastSource) clazz.newInstance();
clazz.invoke("setValue", new Class[] { int.class }, obj, new Object[] { 1 });
clazz.invoke("setOther", new Class[] { int.class }, obj, new Object[] { 2 });
int value = (Integer) clazz.invoke("getValue", new Class[] {}, obj, new Object[] {});
int other = (Integer) clazz.invoke("getOther", new Class[] {}, obj, new Object[] {});
System.out.println(value + " " + other);
// fastMethod使用
FastMethod setValue = clazz.getMethod("setValue", new Class[] { int.class });
System.out.println("setValue index is : " + setValue.getIndex());
FastMethod getValue = clazz.getMethod("getValue", new Class[] {});
System.out.println("getValue index is : " + getValue.getIndex());
FastMethod setOther = clazz.getMethod("setOther", new Class[] { int.class });
System.out.println("setOther index is : " + setOther.getIndex());
FastMethod getOther = clazz.getMethod("getOther", new Class[] {});
System.out.println("getOther index is : " + getOther.getIndex());
System.out.println("getDeclaredMethods : " + clazz.getJavaClass().getDeclaredMethods().length);
System.out.println("getConstructors : " + clazz.getJavaClass().getConstructors().length);
System.out.println("getFields : " + clazz.getJavaClass().getFields().length);
System.out.println("getMaxIndex : " + clazz.getMaxIndex());
class FastSource {
proxy (spring aop相关)
总体类结构图:
Callback & CallbackGenerator
MethodInterceptor
类似于spring aop的around Advise的功能,大家都知道,不多做介绍。唯一需要注意的就是proxy.invokeSuper和proxy.invoke的区别。invokeSuper是退出当前interceptor的处理,进入下一个callback处理,invoke则会继续回调该方法,如果传递给invoke的obj参数出错容易造成递归调用
Dispatcher, ProxyRefDispatcher
类似于delegate的模式,直接将请求分发给具体的Dispatcher调用,是否有着接口+实现分离的味道,将接口的方法调用通过Dispatcher转到实现target上。ProxyRefDispatcher与Dispatcher想比,loadObject()多了个当前代理对象的引用。
//反编译的部分代码
public final int cal(int i, int j)
CGLIB$CALLBACK_1;
if(CGLIB$CALLBACK_1 != null) goto _L2; else goto _L1
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_1;
loadObject(); //每次都进行调用
(DefaultCalcService);
cal(); //调用实现类的方法
LazyLoader
相比于Dispatcher,lazyLoader在第一次获取了loadObject后,会进行缓存,后续的请求调用都会直接调用该缓存的属性.
//反编译部分代码
public final int cal(int i, int j)
return ((DefaultCalcService)CGLIB$LOAD_PRIVATE_3()).cal(i, j);
private final synchronized Object CGLIB$LOAD_PRIVATE_3()
CGLIB$LAZY_LOADER_3; //保存的属性
if(CGLIB$LAZY_LOADER_3 != null) goto _L2; else goto _L1
CGLIB$CALLBACK_3;
if(CGLIB$CALLBACK_3 != null) goto _L4; else goto _L3
CGLIB$BIND_CALLBACKS(this);
CGLIB$CALLBACK_3;
loadObject();
JVM INSTR dup_x1 ;
CGLIB$LAZY_LOADER_3;
不做任何处理,结合Filter针对不需要做代理方法直接返回,调用其原始方法
FixedValue
强制方法返回固定值,可结合Filter进行控制
InvocationHandler(提供和jdk proxy的功能),不常用
CallbackFilter
主要的作用就是callback调度,主要的一个方法:int accept(Method method); 返回的int在int值,代表对应method需要插入的callback,会静态生成到class的代码中,这样是cglib proxy区别于jdk proxy的方式,一个是静态的代码调用,一个是动态的reflect。可以查看: Enhancer类中的emitMethods方法,line:883。在构造class method字节吗之前就已经确定需要运行的callback。
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/home/ljh/cglib");
LogInteceptor logInteceptor = new LogInteceptor();
CalDispatcher calDispatcher = new CalDispatcher();
CalcProxyRefDispatcher calcProxyRefDispatcher = new CalcProxyRefDispatcher();
LazyLoaderCallback lazyLoaderCallback = new LazyLoaderCallback();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CalcService.class); //接口类
enhancer.setCallbacks(new Callback[] { logInteceptor, calDispatcher, calcProxyRefDispatcher,lazyLoaderCallback, NoOp.INSTANCE }); // callback数组
enhancer.setCallbackFilter(new CalcCallbackFilter()); // filter
CalcService service = (CalcService) enhancer.create();
int result = service.cal(1, 1);
(工具类,感觉有点鸡肋)
StringSwitcher 提供string和int的map映射查询,给定一个string字符串,返回同个下标数组的int值,感觉很鸡肋,用Map不是可以很快速的实现功能
ParallelSorter 看了具体的代码,没啥意思,就是提供了一个二分的快速排序和多路归并排序。没有所谓的并行排序,原本以为会涉及多线程处理,可惜没有
暂时没仔细研究,更多的是对asm的封装,等下次看了asm代码后再回来研究下。
相关性能测试和使用说明,可以参见另一篇文章:
浏览 13037
论坛回复 /
(9 / 20952)
你拿到的class不是BeanCopier的class. 这是我的
public class com.agapple.cglib.beans.Target$$BeanCopierByCGLIB$$e1c34377 extends net.sf.cglib.beans.BeanCopier
SourceFile: "&generated&"
minor version: 0
major version: 46
Constant pool:
const #1 = Asciz com/agapple/cglib/beans/Target$$BeanCopierByCGLIB$$e1c34377;而你给的类名是:& public class BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$f32401fd extends KeyFactory你是不是反编译错了另外一个文件?你好,可以打包你的测试代码我看一下吗?谢谢@
希望lz能够在讲的详细点 看着还是有些迷糊
可以看下 cglib相关性能测试对比
那里有一些具体的使用例子,对照例子看可能更容易理解
fuyou001 写道问下楼主,楼主的uml 图是cglib项目自带的,还是楼主自己画的,如果是自己画的,可否告诉是用什么软件画的吗,谢谢
用的是jude免费版,纯java的写的,所以具有跨平台性, linux下使用比较合适。
如果windows可以用用startuml,也是免费的。
推荐一个UML工具Visual Paradigm ,社区版是免费的,也是Java写的,跨平台。
下载地址:
投个精华走人。一年后再来研究。
多谢支持。
对类似jvm字节码的处理学习上的确有点门槛,类似的还有javassist,BCEL,asm
毕竟文档相对少,最好是有一定的业务需求,再去理解一下它的适用场景,再结合一下反编译工具,掌握起来会相对更快
问下楼主,楼主的uml 图是cglib项目自带的,还是楼主自己画的,如果是自己画的,可否告诉是用什么软件画的吗,谢谢
用的是jude免费版,纯java的写的,所以具有跨平台性, linux下使用比较合适。
如果windows可以用用startuml,也是免费的。
浏览: 1230279 次
来自: 杭州
您好,我想咨询一下,开源的canal都能支持mysql的哪些版 ...
copy 一份做记录,后续学习,请知悉
你好,我使用otter中出现了一些问题
“报异常java.r ...
我转载了下,想做个记录。如果不可以转载请告知,谢谢
请教一下,怎么配置group 模式呢?没找到group模式的d ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 abstract class 的文章

 

随机推荐