Java Annotation 高级应用

Java自定义注解Annotation的使用 JPA、EJB、Spring零配置等等怎么使用相信各位读者都能掌握,这里主要是说如何自定义自己的注解,自己使用自定义的注解。 立即下载

 

版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
作者:cleverpig(作者的Blog: http://blog.matrix.org.cn/page/cleverpig )
原文: http://www.matrix.org.cn/resource/article/44/44062_Java+Annotation+Apt.html
关键字:java,annotation,apt

前言:
前不久在matrix上先后发表了 《java annotation 入门》 、 《java annotation 手册》 两 篇文章,比较全面的对java annotation的语法、原理、使用三方面进行了阐述。由于《入门》中的简单例程虽然简单明了的说明了annotation用法,但给大家的感觉可能 是意犹未见,所以在此行文《java annotation高级应用》,具体实例化解释annotation和annotation processing tool(APT)的使用。望能对各位的有所帮助。

一、摘要:
《java annotation高级应用》具体实例化解释annotation和annotation processing tool(APT)的使用。望能对各位的有所帮助。本文列举了用于演示annotation的BRFW演示框架、演示APT的apt代码实例,并对其进行 较为深度的分析,希望大家多多提意见。

二、annotation实例分析
1.BRFW(Beaninfo Runtime FrameWork)定义:
本人编写的一个annotation功能演示框架。顾名思义,BRFW就是在运行时取得bean信息的框架。

2.BRFW的功能:
A.源代码级annotation :在bean的源代码中使用annotation定义bean的信息;
B.运行时获取bean数据 :在运行时分析bean class中的annotation,并将当前bean class中field信息取出,功能类似xdoclet;
C.运行时bean数据的xml绑定 :将获得的bean数据构造为xml文件格式展现。熟悉j2ee的朋友知道,这个功能类似jaxb。

3.BRFW框架:
BRFW主要包含以下几个类:
A.Persistent类 :定义了用于修饰类的固有类型成员变量的annotation。
B.Exportable类 :定义了用于修饰Class的类型的annotation。
C.ExportToXml类 :核心类,用于完成BRFW的主要功能:将具有Exportable Annotation的bean对象转换为xml格式文本。
D.AddressForTest类 :被A和B修饰过的用于测试目的的地址bean类。其中包含了地址定义所必需的信息:国家、省级、城市、街道、门牌等。
E.AddressListForTest类 : 被A和B修饰过的友人通讯录bean类。其中包含了通讯录所必备的信息:友人姓名、年龄、电话、住址(成员为AddressForTest类型的 ArrayList)、备注。需要说明的是电话这个bean成员变量是由字符串类型组成的ArrayList类型。由于朋友的住址可能不唯一,故这里的住 址为由AddressForTest类型组成的ArrayList。
从上面的列表中,可以发现A、B用于修饰bean类和其类成员;C主要用于取出bean类的数据并将其作xml绑定,代码中使用了E作为测试类;E中可能包含着多个D。
在了解了这个简单框架后,我们来看一下BRFW的代码吧!

4.BRFW源代码分析:
A.Persistent类:
清单1:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.lang.annotation.*;

/**
* 用于修饰类的固有类型成员变量的annotation
* @author cleverpig
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Persistent {
        String value() default "";
}


B.Exportable类:
清单2:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.lang.annotation.*;

/**
* 用于修饰类的类型的annotation
* @author cleverpig
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Exportable {
        //名称
        String name() default "";
        //描述
        String description() default "";
        //省略name和description后,用来保存name值
        String value() default "";
        
}


C.AddressForTest类:
清单3:

package com.bjinfotech.practice.annotation.runtimeframework;

/**
* 用于测试的地址类
* @author cleverpig
*
*/
@Exportable("address")
public class AddressForTest {
        //国家
        @Persistent
        private String country=null;
        
        //省级
        @Persistent
        private String province=null;
        
        //城市
        @Persistent
        private String city=null;
        
        //街道
        @Persistent
        private String street=null;

        //门牌
        @Persistent
        private String doorplate=null;
        
        public AddressForTest(String country,String province,
                        String city,String street,String doorplate){
                this.country=country;
                this.province=province;
                this.city=city;
                this.street=street;
                this.doorplate=doorplate;
        }
        
}


D.AddressListForTest类:
清单4:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.util.*;

/**
* 友人通讯录
* 包含:姓名、年龄、电话、住址(多个)、备注
* @author cleverpig
*
*/
@Exportable(name="addresslist",description="address list")
public class AddressListForTest {
        //友人姓名
        @Persistent
        private String friendName=null;
        
        //友人年龄
        @Persistent
        private int age=0;
        
        //友人电话
        @Persistent
        private ArrayList<String> telephone=null;
        
        //友人住址:家庭、单位
        @Persistent
        private ArrayList<AddressForTest> AddressForText=null;
        
        //备注
        @Persistent
        private String note=null;
        
        public AddressListForTest(String name,int age,
                        ArrayList<String> telephoneList,
                        ArrayList<AddressForTest> addressList,
                        String note){
                this.friendName=name;
                this.age=age;
                this.telephone=new ArrayList<String>(telephoneList);
                this.AddressForText=new ArrayList<AddressForTest>(addressList);
                this.note=note;
                
        }
}


E.ExportToXml类:
清单5:

package com.bjinfotech.practice.annotation.runtimeframework;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.ArrayList;

/**
* 将具有Exportable Annotation的对象转换为xml格式文本
* @author cleverpig
*
*/
public class ExportToXml {
        /**
         * 返回对象的成员变量的值(字符串类型)
         * @param field 对象的成员变量
         * @param fieldTypeClass 对象的类型
         * @param obj 对象
         * @return 对象的成员变量的值(字符串类型)
         */
        private String getFieldValue(Field field,Class fieldTypeClass,Object obj){
                String value=null;
                
                try{
                        if (fieldTypeClass==String.class){
                                value=(String)field.get(obj);
                        }
                        else if (fieldTypeClass==int.class){
                                value=Integer.toString(field.getInt(obj));
                        }
                        else if (fieldTypeClass==long.class){
                                value=Long.toString(field.getLong(obj));
                        }
                        else if (fieldTypeClass==short.class){
                                value=Short.toString(field.getShort(obj));
                        }
                        else if (fieldTypeClass==float.class){
                                value=Float.toString(field.getFloat(obj));
                        }
                        else if (fieldTypeClass==double.class){
                                value=Double.toString(field.getDouble(obj));
                        }
                        else if (fieldTypeClass==byte.class){
                                value=Byte.toString(field.getByte(obj));
                        }
                        else if (fieldTypeClass==char.class){
                                value=Character.toString(field.getChar(obj));
                        }
                        else if (fieldTypeClass==boolean.class){
                                value=Boolean.toString(field.getBoolean(obj));
                        }
                }
                catch(Exception ex){
                        ex.printStackTrace();
                        value=null;
                }
                return value;
        }
        
        /**
         * 输出对象的字段,当对象的字段为Collection或者Map类型时,要调用exportObject方法继续处理
         * @param obj 被处理的对象
         * @throws Exception
         */
        public void exportFields(Object obj) throws Exception{
                Exportable exportable=obj.getClass().getAnnotation(Exportable.class);        
                if (exportable!=null){
                        if (exportable.value().length()>0){
//                                System.out.println("Class annotation Name:"+exportable.value());
                        }
                        else{
//                                System.out.println("Class annotation Name:"+exportable.name());
                        }
                }
                else{
//                        System.out.println(obj.getClass()+"类不是使用Exportable标注过的");
                }
                
                //取出对象的成员变量
                Field[] fields=obj.getClass().getDeclaredFields();
                
                for(Field field:fields){
                        //获得成员变量的标注
                        Persistent fieldAnnotation=field.getAnnotation(Persistent.class);
                        if (fieldAnnotation==null){
                                continue;
                        }
                        //重要:避免java虚拟机检查对私有成员的访问权限
                        field.setAccessible(true);
                        Class typeClass=field.getType();
                        String name=field.getName();
                        String value=getFieldValue(field,typeClass,obj);
                        
                        //如果获得成员变量的值,则输出
                        if (value!=null){
                                System.out.println(getIndent()+"<"+name+">/n"
                                                +getIndent()+"/t"+value+"/n"+getIndent()+"</"+name+">");
                        }
                        //处理成员变量中类型为Collection或Map
                        else if ((field.get(obj) instanceof Collection)||
                                        (field.get(obj) instanceof Map)){
                                exportObject(field.get(obj));
                        }
                        else{
                                exportObject(field.get(obj));
                        }
                        
                }
        }
        
        //缩进深度
        int levelDepth=0;
        //防止循环引用的检查者,循环引用现象如:a包含b,而b又包含a
        Collection<Object> cyclicChecker=new ArrayList<Object>();
        
        /**
         * 返回缩进字符串
         * @return
         */
        private String getIndent(){
                String s="";
                for(int i=0;i<levelDepth;i++){
                        s+="/t";
                }
                return s;
        }
        /**
         * 输出对象,如果对象类型为Collection和Map类型,则需要递归调用exportObject进行处理
         * @param obj
         * @throws Exception
         */
        public void exportObject(Object obj) throws Exception{
                Exportable exportable=null;
                String elementName=null;
                
                //循环引用现象处理
                if (cyclicChecker.contains(obj)){
                        return;
                }
                
                cyclicChecker.add(obj);
                
                //首先处理Collection和Map类型
                if (obj instanceof Collection){
                        for(Iterator i=((Collection)obj).iterator();i.hasNext();){
                                exportObject(i.next());
                        }
                }
                else if (obj instanceof Map){
                        for(Iterator i=((Map)obj).keySet().iterator();i.hasNext();){
                                exportObject(i.next());
                        }
                }
                else{

                        exportable=obj.getClass().getAnnotation(Exportable.class);
                        //如果obj已经被Exportable Annotation修饰过了(注意annotation是具有继承性的),
                        //则使用其name作为输出xml的元素name
                        if (exportable!=null){
                                if (exportable.value().length()>0){
                                        elementName=exportable.value();
                                }
                                else{
                                        elementName=exportable.name();
                                }
                        }
                        //未被修饰或者Exportable Annotation的值为空字符串,
                        //则使用类名作为输出xml的元素name
                        if (exportable==null||elementName.length()==0){
                                elementName=obj.getClass().getSimpleName();
                        }
                        //输出xml元素头
                        System.out.println(getIndent()+"<"+elementName+">");
                        levelDepth++;
                        //如果没有被修饰,则直接输出其toString()作为元素值
                        if (exportable==null){
                                System.out.println(getIndent()+obj.toString());
                        }
                        //否则将对象的成员变量导出为xml
                        else{
                                exportFields(obj);
                        }
                        levelDepth--;
                        //输出xml元素结尾
                        System.out.println(getIndent()+"</"+elementName+">");
                        
                }
                cyclicChecker.remove(obj);
        }
        
        public static void main(String[] argv){
                try{
                        AddressForTest ad=new AddressForTest("China","Beijing",
                                        "Beijing","winnerStreet","10");
                        
                        ExportToXml test=new ExportToXml();
                        
                        ArrayList<String> telephoneList=new ArrayList<String>();
                        telephoneList.add("66608888");
                        telephoneList.add("66608889");
                        
                        ArrayList<AddressForTest> adList=new ArrayList<AddressForTest>();
                        adList.add(ad);
                        
                        AddressListForTest adl=new AddressListForTest("coolBoy",
                                        18,telephoneList,adList,"some words");
                        
                        test.exportObject(adl);
                }
                catch(Exception ex){
                        ex.printStackTrace();
                }
        }
}


在ExportToXml类之前的类比较简单,这里必须说明一下ExportToXml类:此类的核心函数是exportObject和 exportFields方法,前者输出对象的xml信息,后者输出对象成员变量的信息。由于对象类型和成员类型的多样性,所以采取了以下的逻辑:

在exportObject方法中,当对象类型为Collection和Map类型时,则需要递归调用exportObject进行处理;
而如果对象类型不是Collection和Map类型的话,将判断对象类是否被Exportable annotation修饰过:
如果没有被修饰,则直接输出<对象类名>对象.toString()</对象类名>作为xml绑定结果的一部分;
如果被修饰过,则需要调用exportFields方法对对象的成员变量进行xml绑定。

在 exportFields方法中,首先取出对象的所有成员,然后获得被Persisitent annotation修饰的成员。在其后的一句:field.setAccessible(true)是很重要的,因为bean类定义中的成员访问修饰都 是private,所以为了避免java虚拟机检查对私有成员的访问权限,加上这一句是必需的。接着后面的语句便是输出<成员名>成员 值</成员名>这样的xml结构。像在exportObject方法中一般,仍然需要判断成员类型是否为Collection和Map类型, 如果为上述两种类型之一,则要在exportFields中再次调用exportObject来处理这个成员。

在main方法中,本人编写了一段演示代码:建立了一个由单个友人地址类(AddressForTest)组成的ArrayList作为通讯录类(AddressForTest)的成员的通讯录对象,并且输出这个对象的xml绑定,运行结果如下:

清单6:

<addresslist>
        <friendName>
                coolBoy
        </friendName>
        <age>
                18
        </age>
        <String>
                66608888
        </String>
        <String>
                66608889
        </String>
        <address>
                <country>
                        China
                </country>
                <province>
                        Beijing
                </province>
                <city>
                        Beijing
                </city>
                <street>
                        winnerStreet
                </street>
                <doorplate>
                        10
                </doorplate>
        </address>
        <note>
                some words
        </note>
</addresslist>


三、APT实例分析:
1.何谓APT?
根 据sun官方的解释,APT(annotation processing tool)是一个命令行工具,它对源代码文件进行检测找出其中的annotation后,使用annotation processors来处理annotation。而annotation processors使用了一套反射API并具备对JSR175规范的支持。
annotation processors处理annotation的基本过程如下:首先,APT运行annotation processors根据提供的源文件中的annotation生成源代码文件和其它的文件(文件具体内容由annotation processors的编写者决定),接着APT将生成的源代码文件和提供的源文件进行编译生成类文件。
简单的和前面所讲的annotation 实例BRFW相比,APT就像一个在编译时处理annotation的javac。而且从sun开发者的blog中看到,java1.6 beta版中已将APT的功能写入到了javac中,这样只要执行带有特定参数的javac就能达到APT的功能。

2.为何使用APT?
使 用APT主要目的是简化开发者的工作量,因为APT可以在编译程序源代码的同时,生成一些附属文件(比如源文件、类文件、程序发布描述文字等),这些附属 文件的内容也都是与源代码相关的。换句话说,使用APT就是代替了传统的对代码信息和附属文件的维护工作。使用过hibernate或者beehive等 软件的朋友可能深有体会。APT可以在编译生成代码类的同时将相关的文件写好,比如在使用beehive时,在代码中使用annotation声明了许多 struct要用到的配置信息,而在编译后,这些信息会被APT以struct配置文件的方式存放。

3.如何定义processor?
A.APT工作过程:
从 整个过程来讲,首先APT检测在源代码文件中哪些annotation存在。然后APT将查找我们编写的annotation processor factories类,并且要求factories类提供处理源文件中所涉及的annotation的annotation processor。接下来,一个合适的annotation processors将被执行,如果在processors生成源代码文件时,该文件中含有annotation,则APT将重复上面的过程直到没有新文 件生成。

B.编写annotation processors:
编写一个annotation processors需要使用java1.5 lib目录中的tools.jar提供的以下4个包:
com.sun.mirror.apt: 和APT交互的接口;
com.sun.mirror.declaration: 用于模式化类成员、类方法、类声明的接口;
com.sun.mirror.type: 用于模式化源代码中类型的接口;
com.sun.mirror.util: 提供了用于处理类型和声明的一些工具。

每 个processor实现了在com.sun.mirror.apt包中的AnnotationProcessor接口,这个接口有一个名为 “process”的方法,该方法是在APT调用processor时将被用到的。一个processor可以处理一种或者多种annotation类 型。
一个processor实例被其相应的工厂返回,此工厂为AnnotationProcessorFactory接口的实现。APT将调用工 厂类的getProcessorFor方法来获得processor。在调用过程中,APT将提供给工厂类一个 AnnotationProcessorEnvironment 类型的processor环境类对象,在这个环境对象中,processor将找到其执行所需要的每件东西,包括对所操作的程序结构的参考,与APT通讯 并合作一同完成新文件的建立和警告/错误信息的传输。

提供工厂类有两个方式:通过APT的“-factory”命令行参数提供,或者让工厂类在APT的发现过程中被自动定位(关于发现过程详细介绍请看 http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html )。前者对于一个已知的factory来讲是一种主动而又简单的方式;而后者则是需要在jar文件的META-INF/services目录中提供一个特定的发现路径:
在 包含factory类的jar文件中作以下的操作:在META-INF/services目录中建立一个名为 com.sun.mirror.apt.AnnotationProcessorFactory 的UTF-8编码文件,在文件中写入所有要使用到的factory类全名,每个类为一个单独行。

4.一个简单的APT实例分析:
A.实例构成:
Review类:定义Review Annotation;
ReviewProcessorFactory类:生成ReviewProcessor的工厂类;
ReviewProcessor类:定义处理Review annotation的Processor;
ReviewDeclarationVisitor类:定义Review annotation声明访问者,ReviewProcessor将要使用之对Class进行访问。
runapt.bat:定义了使用自定义的ReviewProcessor对Review类源代码文件进行处理的APT命令行。

B.Review类:
清单7:

package com.bjinfotech.practice.annotation.apt;

/**
* 定义Review Annotation
* @author cleverpig
*
*/
public @interface Review {
        public static enum TypeEnum{EXCELLENT,NICE,NORMAL,BAD};
        TypeEnum type();
        String name() default "Review";
}


C.ReviewProcessorFactory类:
清单8:

package com.bjinfotech.practice.annotation.apt;

import java.util.Collection;
import java.util.Set;
import java.util.Arrays;
import com.sun.mirror.apt.*;
import com.sun.mirror.declaration.AnnotationTypeDeclaration;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
//请注意为了方便,使用了静态import
import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.emptySet;

/**
* 生成ReviewProcessor的工厂类
* @author cleverpig
*
*/
public class ReviewProcessorFactory implements AnnotationProcessorFactory{
        /**
         * 获得针对某个(些)类型声明定义的Processor
         * @param atds 类型声明集合
         * @param env processor环境
         */
        public AnnotationProcessor getProcessorFor(
                        Set<AnnotationTypeDeclaration> atds,
                        AnnotationProcessorEnvironment env){
                return new ReviewProcessor(env);
        }
        /**
         * 定义processor所支持的annotation类型
         * @return processor所支持的annotation类型的集合
         */
        public Collection<String>         supportedAnnotationTypes(){
                //“*”表示支持所有的annotation类型
                //当然也可以修改为“foo.bar.*”、“foo.bar.Baz”,来对所支持的类型进行修饰
            return unmodifiableCollection(Arrays.asList("*"));
    }
        
        /**
         * 定义processor支持的选项
         * @return processor支持选项的集合
         */
        public Collection<String>         supportedOptions(){
                //返回空集合
            return emptySet();
    }
        
        public static void main(String[] argv){
                System.out.println("ok");
        }
}


D.ReviewProcessor类:
清单9:

package com.bjinfotech.practice.annotation.apt;

import com.sun.mirror.apt.AnnotationProcessor;
import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.util.DeclarationVisitors;
import com.sun.mirror.util.DeclarationVisitor;

/**
* 定义Review annotation的Processor
* @author cleverpig
*
*/
public class ReviewProcessor implements AnnotationProcessor{
        //Processor所工作的环境
        AnnotationProcessorEnvironment env=null;
        
        /**
         * 构造方法
         * @param env 传入processor环境
         */
        public ReviewProcessor(AnnotationProcessorEnvironment env){
                this.env=env;
        }
        
        /**
         * 处理方法:查询processor环境中的类型声明,
         */
        public void process(){
                //查询processor环境中的类型声明
                for(TypeDeclaration type:env.getSpecifiedTypeDeclarations()){
                        //返回对类进行扫描、访问其声明时使用的DeclarationVisitor,
                        //传入参数:new ReviewDeclarationVisitor(),为扫描开始前进行的对类声明的处理
                        //        DeclarationVisitors.NO_OP,表示在扫描完成时进行的对类声明不做任何处理
                        DeclarationVisitor visitor=DeclarationVisitors.getDeclarationScanner(
                                        new ReviewDeclarationVisitor(),DeclarationVisitors.NO_OP);
                        //应用DeclarationVisitor到类型
                        type.accept(visitor);
                }
        }
}


E.ReviewDeclarationVisitor类:
清单10:

package com.bjinfotech.practice.annotation.apt;

import com.sun.mirror.util.*;
import com.sun.mirror.declaration.*;

/**
* 定义Review annotation声明访问者
* @author cleverpig
*
*/
public class ReviewDeclarationVisitor extends SimpleDeclarationVisitor{
        /**
         * 定义访问类声明的方法:打印类声明的全名
         * @param cd 类声明对象
         */
        public void visitClassDeclaration(ClassDeclaration cd){
                System.out.println("获取Class声明:"+cd.getQualifiedName());
        }
        
        public void visitAnnotationTypeDeclaration(AnnotationTypeDeclaration atd){
                System.out.println("获取Annotation类型声明:"+atd.getSimpleName());
        }
        
        public void visitAnnotationTypeElementDeclaration(AnnotationTypeElementDeclaration aed){
                System.out.println("获取Annotation类型元素声明:"+aed.getSimpleName());
        }
}


F.runapt.bat文件内容如下:
清单11:

E:
rem 项目根目录
set PROJECT_ROOT=E:/eclipse3.1RC3/workspace/tigerFeaturePractice
rem 包目录路径
set PACKAGEPATH=com/bjinfotech/practice/annotation/apt
rem 运行根路径
set RUN_ROOT=%PROJECT_ROOT%/build
rem 源文件所在目录路径
set SRC_ROOT=%PROJECT_ROOT%/test
rem 设置Classpath
set CLASSPATH=.;%JAVA_HOME%;%JAVA_HOME%/lib/tools.jar;%RUN_ROOT%

cd %SRC_ROOT%/%PACKAGEPATH%
apt -nocompile -factory com.bjinfotech.practice.annotation.apt.ReviewProcessorFactory  ./*.java


四、参考资源:
http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html
作者的Blog: http://blog.matrix.org.cn/page/cleverpig


五、源代码下载:
[ 下载文件 ]
老服务器焕新记:在Dell R730上折腾Nvidia K80显卡的完整记录(含Anaconda环境配置) 本文详细记录了在Dell R730服务器上为Nvidia K80计算卡安装驱动、配置CUDA及Anaconda环境的完整过程。文章重点解决了老旧硬件与CentOS 7系统的兼容性问题,提供了从BIOS设置、驱动版本精准匹配到Python机器学习环境搭建的实战指南,旨在帮助读者低成本挖掘旧服务器的GPU计算潜力。 阅读详情

相关推荐

软考中级-系统集成项目管理工程师**的超详细知识点笔记。

软考中级系统集成项目管理工程师核心知识点摘要 综合知识:涵盖信息化基础(国家信息化六要素、信息系统开发方法)、系统集成特点(高技术性、团队协作)、IT服务管理(ITIL流程)、网络技术(OSI模型、TCP/IP)、信息安全(CIA三要素、加密技术)、软件工程(生命周期、测试类型)、面向对象分析与设计(UML图)、新一代信息技术(云计算、大数据、物联网)。 案例分析:聚焦项目管理十大知识领域,重点包括: 整体管理(项目章程、变更控制流程) 范围管理(WBS分解、需求跟踪矩阵) 进度管理

最爱で毛毛熊的博客 1991

【转】自定义 Java Annotation

1. 基本语法 Java代码 packageorg.denger.annotation.example; importjava.lang.annotation.ElementType; importjava.lang.annotation.Target; //The@Bindtag. @Target(Ele...

weixin_30951231的博客 156

生成式引擎优化(GEO)全流程解析

生成式引擎优化(GEO)已成为AI时代数字营销新趋势,通过优化企业内容以提升在AI生成答案中的引用率。本文系统梳理了GEO优化的完整流程,包括:1)前期准备与市场调研;2)数据治理与知识库构建;3)模型适配与算法优化;4)内容权威性建设;5)本地化营销;6)效果监测与优化。研究显示,实施GEO的企业AI曝光率提升62%,转化率增长2.3倍。未来GEO将向多模态内容、实时个性化、垂直场景深化方向发展。企业需建立动态知识图谱,采用结构化数据标记,持续优化内容策略,以在AI搜索时代获取流量优势。

解锁AI流量新红利!🚀 GEO优化(生成引擎优化)助您掌控AI搜索,让AI成为您的品牌最佳代言人! 3248

Java注解实现拦截

Java注解实现拦截 Leave a reply 一个很常见的场景是对方法进行拦截,比如计算方法的执行时间或者判断是否有执行该方法的权限。常用的拦截框架有AOP和aspectj,这两种拦截器使用不同的原理。AOP使用动态代理Bean来实施拦截,而aspectj使用扫描将字节码写入class文件。在这里我想要实现的是一种比较优雅的拦截方式:使用注解静态拦截,但是并不使用扫描。比如

mayimchen的专栏 8019

Python爬虫实战:5分钟搞定东方财富A股数据抓取(附完整代码)

本文提供了一套基于Python的A股数据自动化采集与分析系统构建方案。文章详细解析了如何通过稳健的爬虫框架从东方财富等公开数据源高效抓取A股数据,并设计数据库进行自动化存储与管理,特别适合量化研究和数据分析场景。

weixin_29062963的博客 4436

LBM模式学习·保姆级安装及初步使用教程

在学习LBM的过程中,我感觉可供参考的材料较为有限,对于一个独立学习LBM模式的初学者非常不友好(我就是这个初学者哈哈),因此萌生了写一篇保姆级的LBM模式教程,并将我踩过的坑一一指出,有助于后来者更快地上手该模式,而非半途而废。

weixin_42762673的博客 1万+

注解与反射

注解与反射 文章目录注解与反射一、内置注解二、元注解三、自定义注解四、Java反射机制4.1静态语言与动态语言4.2反射(Reflection)4.3 反射机制的应用4.4 反射的优点与缺点4.5 反射相关的API五、Class类5.1概要5.2 获得Class对象的途径5.3 Class类的常用方法六、类的加载与ClassLoader6.1 Java内存分析6.2 类的加载与ClassLoad...

junjie886的博客 549

[SV]SystemVerilog学习笔记之struct & union

SystemVerilog学习笔记(四) 一、结构体(struct) 1.1、结构体(struct) 结构体声明:结构体默认是变量,也可以声明为线网 var struct{ //通过var进行结构体变量声明 logic [31:0] a, b; logic [ 7:0] opcode; } Instruction_Word_var; wire struct{ //结构体线网声明,定义为线网类型时,结构体的所有成员必须...

元直的博客 1万+

java annotation应用_Java Annotation 高级应用

前言:前不久在matrix上先后发表了《java annotation 入门》、《java annotation 手册》两篇文章,比较全面的对java annotation的语法、原理、使用三方面进行了阐述。由于《入门》中的简单例程虽然简单明了的说明了annotation用法,但给大家的感觉可能是意犹未见,所以在此行文《java annotation高级应用》,具体实例化解释annotation和...

weixin_39914243的博客 241

不会C# Winform用户界面设计?是因为没有掌握这些控件(建议收藏)

文章目录6.1 常用控件6.1.1 单选按钮(RadioButton)6.1.2 复选框(CheckBox)6.1.3 框架1. 面板控件Panel2. 分组框GroupBox3. TabControl控件6.1.4 应用实例6. 2 列表框和组合框6.2.1 列表框(ListBox)6.2.2 组合框(ComboBox )6.2.3 应用实例6.3 用户交互界面6.3.1 滚动条和进度条6.3.2 定时器6.3.3 菜单设计菜单设计概述MenuStrip和ContextMenuSt

智慧空间实验室 2920

Python爬虫实战:如何通过解析JSON数据抓取抖音视频评论

本文介绍了如何使用Python爬虫抓取抖音视频评论数据。请求头伪造:通过使用随机的User-Agent,模拟真实用户的请求。代理池:使用代理IP来避免被封禁。JSON解析:直接从API接口获取JSON格式的数据,避免了动态加载内容的限制。需要注意的是,抓取网站数据时应遵守网站的爬虫协议,避免过度抓取影响网站性能或违反法律法规。希望本文能够帮助你掌握如何抓取和分析抖音视频评论数据!

2201_76125261的博客 3362

Java Annotation高级应用

版权声明:本文可以自由转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明 作者:cleverpig(作者的Blog:http://blog.matrix.org.cn/page/cleverpig) 原文:http://www.matrix.org.cn/re

GrayDay 681

Codex入门24-效率倍增秘籍(终极总结:10个让你开发速度翻倍的Codex高级技巧)

专栏收官之作!经过前23篇的系统学习,你已经掌握了 Codex CLI 的核心用法。本文浓缩10个实战验证的高级技巧:管道化提示词将复杂任务拆成递进指令链,模板化 SKILL.md 打造个人技能库,Shell 别名让操作快如闪电,多模型切换省钱又高效……这不是理论课,每个技巧都配有可直接运行的代码。掌握全部10招,构建你的 AI 开发工作流闭环,让开发速度真正翻倍!

yueyeguzhuo的专栏 191

java annotation应用_Java Annotation高级应用

前言:在此行文《java annotation高级应用》,具体实例化解释annotation和annotation processing tool(APT)的使用。望能对各位的有所帮助。一、摘要:《java annotation高级应用》具体实例化解释annotation和annotation processing tool(APT)的使用。望能对各位的有所帮助。本文列举了用于演示annotati...

weixin_39999586的博客 152

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

上一篇: Java Annotation手册
下一篇: ThreadLocal 介绍
jackoo
博客等级 码龄18年 5粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值