Java反射(三)
目录
1.反射与代理设计模式
2.反射与Annotation
3.自定义Annotation
4.Annotation整合工厂设计模式和代理设计模式
1.反射与代理设计模式
代理模式是指通过业务真实类实现业务接口,再通过设置代理类创建业务真实类子类从而间接访问业务真实类。但是这存在一个弊端,如果有1000个业务接口,对应的业务就需要实例化1000个对象,如下
代理设计模式
package Example1709;
//业务接口实现发送消息
interface Message{public void send();
}
//业务接口真实实现
class MessageReal implements Message{@Overridepublic void send() {System.out.println("传输信息Message");}
}
//代理类
class Proxy{
// 通过实例化子类进行间接实现功能private MessageReal real = new MessageReal();public void getMessage() {real.send();}
}
public class javaDemo {public static void main(String[] args) {Proxy p = new Proxy();p.getMessage();}
}
可以看到代理类里面创建了Message实例对象,通过代理设计就可以实现客户端无需创建相应对象就能调用其中方法,只需要创建代理类即可。但是如果业务非常多,而我仅需要其中一个业务功能,那么代理类创建的对象将浪费。所以可以通过反射实现动态代理
java中特地有InvocationHandle接口实现动态代理,只需要让代理类实现该接口并且覆写其中方法invoke()方法调用 就能实现动态代理
案例代码:
package Example1710;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//业务接口
@FunctionalInterface
interface Message{public void send();
}
interface Connect{public boolean connect();
}
interface Close{public void close();
}
//业务实现类
class MessageReal implements Message{@Overridepublic void send() {System.out.println("输出信息");}
}
class ConnectReal implements Connect{@Overridepublic boolean connect() {System.out.println("连接成功");return true;}
}
class closeReal implements Close{@Overridepublic void close() {System.out.println("断开连接");}
}
//代理类需要实现InvocationHandle接口
class MessageProxy implements InvocationHandler {private Object object;public Object bind(Object object){this.object = object;return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);}
//覆写InvocationHandle接口中的invoke方法实现方法的调用@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("当调用方法时候自动执行这个函数");Object returnData = null;returnData = method.invoke(this.object,args);return returnData;}
}
public class javaDemo {public static void main(String[] args) {
// 向上转型实现需要的代理类Connect con = (Connect) new MessageProxy().bind(new ConnectReal());con.connect();}
}
2.反射与Annotation
在java.lang.reflect中通过AccesibleObject类可以获取Annotation(注解)。
AccessibleObject类获取Annotation的方法:
方法名 | 返回类型 | 描述 |
---|---|---|
getAnnotations() | Annotation[] | 返回直接存在于此元素上的所有注解。 |
getAnnotation(Class<T> annotationClass) | <T extends Annotation> T | 如果此元素上存在指定类型的注解,则返回该注解;否则返回 null 。 |
getDeclaredAnnotations() | Annotation[] | 返回直接存在于此元素上的所有已声明注解。 |
getDeclaredAnnotation(Class<T> annotationClass) | <T extends Annotation> T | 如果此元素上存在指定类型的注解,则返回该注解;否则返回 null 。 |
isAnnotationPresent(Class<? extends Annotation> annotationClass) | boolean | 如果此元素上存在指定类型的注解,则返回 true ;否则返回 false 。 |
案例代码:
package Example1711;import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;@Deprecated
@FunctionalInterface
interface Face{void face();
}@SuppressWarnings("serial")
class Test implements Face, Serializable {@Overridepublic void face() {System.out.println("No face");}
}public class javaDemo {public static void main(String[] args) {Annotation tation[] = Face.class.getAnnotations();for (Annotation temp:tation) {System.out.println(temp);}Annotation taion2[] = Test.class.getAnnotations();for (Annotation temp:taion2) {System.out.println(temp);}}
}
上图中可以发现输出的只有interface接口的注解Annotation 但是类的上面的还有类内部的@Override却没有输出。原因在于Annotation的定义范围有关
下面任意拆出一个注解比如@FunctionInterface,分析源码
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionalInterface{}
可以看到其中还定义的范围是Rentention,这里是RUNTIME意思是运行,
@Retention
注解用于指定注解的保留策略,有三个可选值:
RetentionPolicy.SOURCE
:注解只保留在源代码中,编译时会被忽略。RetentionPolicy.CLASS
:注解保留在编译后的字节码文件中,但在运行时无法获取到。RetentionPolicy.RUNTIME
:注解保留在编译后的字节码文件中,并且可以在运行时通过反射获取到。
问1:Connect con = (Connect) new MessageProxy().bind(new ConnectReal());其中new MessageProxy是创建代理对象,那return Proxy.newProxyInstance(object.getClass().getClassLoader(),this)也是创建代理对象,这不是重复了操作吗,如果和new MessageProxy作用不一样的话,那么newProxyInstance方法有什么作用
3.自定义Annotation
开发者可以根据自己的需要自定义Annotation,其中定义Annotaion时候需要使用@interface进行标记,同时通过@Target定义范围
Annotation操作范围:
元素类型 | @Target 取值 | 描述 |
---|---|---|
类或接口 | ElementType.TYPE | 应用于类、接口或枚举类型。 |
字段 | ElementType.FIELD | 应用于字段(成员变量)。 |
方法 | ElementType.METHOD | 应用于方法。 |
构造方法 | ElementType.CONSTRUCTOR | 应用于构造方法。 |
方法参数 | ElementType.PARAMETER | 应用于方法的参数。 |
局部变量 | ElementType.LOCAL_VARIABLE | 应用于局部变量。 |
注解 | ElementType.ANNOTATION_TYPE | 应用于注解类型。 |
包 | ElementType.PACKAGE | 应用于包声明。 |
泛型类型参数 | ElementType.TYPE_PARAMETER | 应用于泛型类型参数。 |
泛型类型参数的边界 | ElementType.TYPE_USE | 应用于泛型类型参数的使用处,例如类型转换、instanceof 表达式等 |
类型导入声明(Java 9+) | ElementType.TYPE_IMPORT_DECLARATION | 应用于类型导入声明。 |
模块导入声明(Java 9+) | ElementType.MODULE_IMPORT_DECLARATION | 应用于模块导入声明。 |
类型使用 | ElementType.TYPE_USE 或 ElementType.TYPE_PARAMETER | 应用于类型使用或泛型类型参数。 |
自定义案例代码:
如果@DefaultInterface对象有必要的数据传入,可以在@interface下设置value值。
package Example1713;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface useMessage{public String title();public String value();public String Default()default "默认值,如果调用则返回这个默认";
}class Message {@useMessage(title="Annotation的使用标题",value = "value的值")public void send(String str){System.out.println("输出信息"+str);}
}
public class javaDemo {public static void main(String[] args) throws Exception{String str;
// 调用方法Method mehod = Message.class.getMethod("send", String.class);
// 获取指定的AnnotationuseMessage msg = mehod.getAnnotation(useMessage.class);str = msg.Default();
// 实现方法调用mehod.invoke(Message.class.getDeclaredConstructor().newInstance(),str);str = msg.title();mehod.invoke(Message.class.getDeclaredConstructor().newInstance(),str);str = msg.value();mehod.invoke(Message.class.getDeclaredConstructor().newInstance(),str);}
}
4.Annotation整合工厂设计模式和代理设计模式
使用Annotation进行开发时候最大的特点就是可以将相应的配置信息写入Annotation后,在项目启动的时候就能够通过反射获取到相应的Annotation定义并操作
以下案例实现了通过Annotation整合工厂设计模式和代理设计模式
案例代码:
package Example1714;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;//业务接口
interface Message{public void send(String msg);
}
//业务实现类
class NetMessageImp implements Message{@Overridepublic void send(String msg) {System.out.println("通过网络进行发送消息"+msg);}
}
class CloudMessageImp implements Message{@Overridepublic void send(String msg) {System.out.println("通过云网络进行发送消息"+msg);}
}
//定义工厂类
class Factory{
// 私有化工厂类无法在外部实例化private Factory(){};
// 通过getInstance获取实例化的对象public static<T> T getInstance(Class<T> clazz){try {return (T) new MessageProxy().bind(clazz.getDeclaredConstructor().newInstance());} catch (Exception e){e.printStackTrace();return null;}}
}
//设置自定义Annotation
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface RealInstance {public Class<?> claszz();}@RealInstance(claszz = NetMessageImp.class)
class MessageService{private Message msg;public MessageService(){
// getAnnotation需要对应的classRealInstance cls = MessageService.class.getAnnotation(RealInstance.class);this.msg = (Message) Factory.getInstance(cls.claszz());}public void send(String msg){this.msg.send(msg);}
}
//设置代理类
class MessageProxy implements InvocationHandler{private Object target;
// 绑定并创建指定对象public Object bind(Object target){this.target = target;return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);}
// 设置连接函数public boolean connect(){System.out.println("连接成功");return true;}
// 设置关闭函数public void close(){System.out.println("断开连接");}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if (this.connect()){return method.invoke(this.target,args);}}catch (Exception e){e.printStackTrace();}finally {this.close();}return null;}
}
public class javaDemo {public static void main(String[] args) {MessageService instance = new MessageService();instance.send("我去,这东西是真的复杂啊,需要好好仔细读完啊");}
}
Message
接口是一个业务接口,定义了发送消息的方法。NetMessageImp
和CloudMessageImp
是两个实现了Message
接口的具体业务类,分别通过网络和云网络发送消息。Factory
是一个工厂类,通过使用代理模式创建并返回代理对象的实例。RealInstance
是一个自定义注解,用于标记需要被代理的具体业务类。MessageService
是一个具有注解的类,其中msg
字段是通过工厂类创建的代理对象,用于发送消息。MessageProxy
是一个实现了InvocationHandler
接口的代理类,负责在发送消息前后进行额外的处理,比如连接和关闭连接。- 在主函数中,创建
MessageService
实例并调用send
方法发送消息。
问1:public static<T> T getInstance(Class<T> clazz)为什么要用<T>,作为泛型方法是如何使用的?
public static <T> T getInstance(Class<T> clazz)
中的<T>
是泛型声明,它允许我们在方法中使用泛型类型。其中,T
是一个类型参数,表示方法的返回类型和传入参数的类型。通过在方法声明中使用泛型,我们可以在调用时指定具体的类型,并在编译时进行类型检查。
问2:在这段整合工厂设计和代理设计时候,工厂类和代理类分别担任了什么样的角色?他们完成了什么职责,为什么要加入MessageService?
- 工厂类(
Factory
)的角色是创建并返回代理对象的实例。它的职责是根据传入的业务接口类型,使用代理模式创建该接口的代理对象。工厂类的目的是为了提供一种通用的方式来创建代理对象。- 代理类(
MessageProxy
)的角色是实现了InvocationHandler
接口的代理类。它的职责是在代理对象的方法调用前后进行额外的处理。在这个例子中,它负责在发送消息前后进行连接和关闭连接的操作。MessageService
是一个业务类,其中的msg
字段通过工厂类创建的代理对象,用于发送消息。MessageService
通过使用代理对象,可以在发送消息的过程中加入额外的处理逻辑,而无需直接引用具体的业务实现类。
问3:Proxy.newProxyInstance()方法如何使用,该怎么传入参数?
Proxy.newProxyInstance()
方法用于创建代理对象。它接受三个参数:
ClassLoader loader
:类加载器,用于在运行时加载代理类。一般可以使用业务接口的类加载器。Class<?>[] interfaces
:代理类要实现的接口数组。代理对象将实现这些接口,并将方法调用委托给InvocationHandler
的invoke()
方法。InvocationHandler h
:代理对象在方法调用时的处理器,需要实现InvocationHandler
接口
问4:方法调用method.invoke()如何传入参数?
问4:
method.invoke()
方法用于调用代理对象的方法。它接受两个参数:
Object obj
:方法所属的对象,即代理对象。Object... args
:方法的参数数组。
问5:在设计模式中,工厂设计模式,代理设计模式,业务处理类的作用?
- 在设计模式中,工厂模式的作用是将对象的创建过程封装起来,并且提供一个统一的接口来获取对象的实例。通过使用工厂类,可以实现对象的创建和管理的解耦,使得代码更加灵活和可维护。
- 代理模式的作用: 代理模式充当了客户端和实际业务对象之间的中介角色,为客户端提供一种间接访问对象的方式。具体来说,代理类封装了实际业务对象并提供了一个类似的接口,使得客户端可以通过代理类来访问实际业务对象。代理类还可以在访问被代理对象之前或之后执行额外的逻辑(例如验证、缓存、日志记录等)。代理模式的优点是它可以在不修改客户端的情况下对实际业务对象进行控制和扩展。
- 业务处理类的作用: 业务处理类是实际执行业务逻辑的类。它是根据特定需求实现业务功能的地方。在代理模式中,业务处理类是被代理的真实对象。它定义了代理类需要代理的具体业务逻辑,代理类会将请求传递给业务处理类并最终由业务处理类完成实际的业务操作。