反射技术
Java的反射技术能够通过配置类的全限定名、方法和参数完成对象的初始化,甚至反射某些方法,大大的增强了Java的可配置型,这也是Spring IoC的底层原理,Java的反射技术覆盖面很广,包括对象构建、反射方法、注解、参数、接口等等,而这一切都是通过
java.lang.reflect.*
来完成的
通过反射构建对象
java
package com.ssm.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 反射服务实现类
*/
public class ReflectServiceImpl{
/**
* 向指定名字的人打招呼
* @param name 人的名字
*/
public static string sayHello(String name)
{
System.out.println( "Hello"+name);
return string;
}
/**
* 获取ReflectServiceImpl类的实例
* 通过反射获取无参构造函数创建实例
* @return 返回ReflectServiceImpl类的实例
*/
public static ReflectServiceImpl getInstance(){
ReflectServiceImpl object = null;
try {
//通过反射获取类的无参构造函数
Constructor<ReflectServiceImpl> constructor = ReflectServiceImpl.class.getConstructor();
//通过构造函数创建实例
object = constructor.newInstance();
}catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException| InvocationTargetException e){
//捕获反射过程中可能抛出的异常
e.printStackTrace();
}
return object;
}
}
java
package com.ssm.reflect;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* ReflectServiceImpl类的测试类,用于测试其功能的正确性。
*/
public class ReflectServiceImplTest {
/**
* 测试sayHello方法是否能正确地返回拼接好的字符串。
* 参数:无
* 返回值:无
*/
@Test
public void testSayHello() {
ReflectServiceImpl service = ReflectServiceImpl.getInstance();
String string = ReflectServiceImpl.sayHello("Tom");
assertEquals("Tom", string); // 验证返回的字符串是否为"HelloTom"
}
/**
* 测试GetInstance方法是否能返回非空的ReflectServiceImpl实例。
* 参数:无
* 返回值:无
*/
@Test
public void testGetInstance() {
ReflectServiceImpl service = ReflectServiceImpl.getInstance();
assertNotNull(service); // 确保返回的实例不为空
}
/**
* 测试GetInstance方法是否每次调用都返回相同的实例。
* 参数:无
* 返回值:无
*/
@Test
public void testSameInstance() {
ReflectServiceImpl service1 = ReflectServiceImpl.getInstance();
ReflectServiceImpl service2 = ReflectServiceImpl.getInstance();
assertNotSame(service1, service2);
}
}
java
package com.ssm.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 这是一个通过反射机制实现的示例服务类,演示了如何通过反射创建实例。
*/
public class ReflectServiceImplII {
private String name; // 姓名字段
/**
* 构造函数,用于初始化对象的name属性。
*
* @param name 传入的姓名字符串。
*/
public ReflectServiceImplII(String name){
this.name = name;
}
/**
* 静态方法,用于打印问候语。
*
* @param name 传入的姓名,将被用于构造问候语。
*/
public static void sayHello(String name)
{
System.out.println( "Hello"+name);
}
/**
* 静态方法,用于通过反射机制创建ReflectServiceImplII的实例。
*
* @return 返回通过反射创建的ReflectServiceImplII实例。
*/
public static ReflectServiceImplII getInstance(){
ReflectServiceImplII object = null;
try {
// 通过反射获取带有String参数的构造函数
Constructor<ReflectServiceImplII> constructor = ReflectServiceImplII.class.getConstructor(String.class);
// 使用反射调用构造函数创建实例
object = constructor.newInstance("Davie yang");
}catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException| InvocationTargetException e){
e.printStackTrace();
}
return object;
}
}
java
package com.ssm.reflect;
import org.junit.Test;
import static org.junit.Assert.*;
public class ReflectServiceImplIITest {
@Test
public void testGetInstance() {
ReflectServiceImplII instance = ReflectServiceImplII.getInstance();
instance.sayHello("Davie yang");
assertNotNull(instance);
assertEquals("HelloDavie yang", instance.sayHello("Davie yang"));
}
}
反射的优点在于只要配置就可以生成对象,可以解除程序的耦合度,比较灵活,其缺点是运行相对较慢,反射技术在系统架构中的使用如何取舍是关键,Spring IoC技术就广泛的使用了发射
通过反射构建方法
java
package com.ssm.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 反射服务实现类,提供反射机制调用方法的功能演示
*/
public class ReflectServiceImplIII {
/**
* 向指定名字的人打招呼
*
* @param name 人的名字
* @void 方法没有返回值
*/
public static void sayHello(String name) {
System.out.println("Hello" + name);
}
/**
* 通过反射机制调用sayHello方法
*
* @return 返回反射调用方法的返回对象,本例中为null,因为sayHello方法没有返回值
*/
public Object reflectMethod() {
Object returnObj = null;
ReflectServiceImplIII target = new ReflectServiceImplIII();
try {
// 获取sayHello方法的Method实例,包括其参数类型
Method method = ReflectServiceImplIII.class.getMethod("sayHello", String.class);
// 通过Method实例调用sayHello方法,传入参数"小明" 完成反射
returnObj = method.invoke(target, "小明");
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
// 捕获反射调用中可能出现的异常,并打印堆栈信息
e.printStackTrace();
}
return returnObj;
}
}
实例
java
package com.ssm.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 反射服务实现类,提供反射机制调用方法的功能演示
*/
public class ReflectServiceImplIII {
/**
* 向指定名字的人打招呼
*
* @param name 人的名字
* @void 方法没有返回值
*/
public static String sayHello(String name) {
System.out.println("Hello" + name);
return "Hello"+name;
}
/**
* 通过反射机制调用sayHello方法
*
* @return 返回反射调用方法的返回对象,本例中为null,因为sayHello方法没有返回值
*/
public static Object reflectMethod() {
ReflectServiceImplIII object = null;
String s = null;
try {
Constructor<ReflectServiceImplIII> constructor = ReflectServiceImplIII.class.getConstructor();
object = constructor.newInstance();
// 获取sayHello方法的Method实例,包括其参数类型
Method method = object.getClass().getMethod("sayHello", String.class);
// 通过Method实例调用sayHello方法,传入参数"小明"
s = (String) method.invoke(object, "小明");
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException |
InvocationTargetException|InstantiationException e) {
// 捕获反射调用中可能出现的异常,并打印堆栈信息
e.printStackTrace();
}
return s;
}
}
java
package com.ssm.reflect;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class ReflectServiceImplIIITest {
@Test
public void testReflectMethod() {
String result = (String) ReflectServiceImplIII.reflectMethod();
assertEquals("Hello小明", result);
}
}
对象在反射机制下生成后,反射了方法,如此便可以通过配置来完成对象和方法的反射,从而增强了可配置性和可扩展性,SpringIoC就是一个典型的样例
动态代理模式和责任链模式
代理模式的意义在于生成一个占位(代理对象),来代理真实对象(目标对象),从而控制真实对象的访问,动态代理和责任链无论在Spring还是在MyBatis中都有重要的应用
- 代理对象的作用是在访问真实对象之前或者之后加入对应的逻辑,或者根据规则控制决定是否使用真实对象,因此代理必须包含两个步骤其一是建立代理对象和真实对象之间的代理关系,其二是实现代理对象的代理逻辑方法;
- 在Java中有多种动态代理技术,比如JDK、CGLIB、Javassist、ASM等,最常用的是JDK动态代理,它是JDK自带的功能,另一种是CGLIB动态代理,这是第三方技术,在JDK的动态代理中必须使用接口而CGLIB不需要用起来更简便
- Spring中常用JDK和CGLIB,而MyBatis还是用了Javassist
JDK动态代理
真实对象
java
package com.ssm.proxy;
public interface HelloWorld {
public void sayHelloWorld();
}
java
package com.ssm.proxy.impl;
import com.ssm.proxy.HelloWorld;
public class HelloWorldImpl implements HelloWorld {
@Override
public void sayHelloWorld() {
System.out.println("Hello World!");
}
}
代理对象
java
package com.ssm.proxy.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
/**
* JDK动态代理示例类,实现InvocationHandler接口。
* 用于创建一个代理对象,该代理对象可以在调用方法前后添加额外的操作。
*/
public class JDKProxyExample implements InvocationHandler {
private Object target = null;
/**
* 绑定目标对象,返回一个代理对象。
*
* @param target 目标对象,将为目标对象创建一个代理。
* @return 返回代理对象,该对象实现了目标对象的所有接口。
*/
public Object bind(Object target) {
this.target = target;
// 使用JDK动态代理生成一个代理实例
// newProxyInstance方法的三个参数意义重大,第一个是类的加载器,此处就是target的类加载器,
// 第二个是目标对象实现的接口,此处就是target实现的所有接口
// 第三个参数是InvocationHandler的实现类,此处用到this就是JDKProxyExample的实现类
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* 当调用代理对象的方法时,实际上会调用此方法。
*
* @param proxy 代理对象本身。
* @param method 被调用的方法。
* @param args 方法调用时传递的参数。
* @return 方法的返回值。
* @throws Throwable 如果方法执行抛出异常,则抛出此异常。
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法执行前的操作
System.out.println("before");
// 调用目标对象的方法,也是通过反射实现的
Object result = method.invoke(target, args);
// 方法执行后的操作
System.out.println("after");
return result;
}
}
在JDK动态代理中,要实现代理逻辑类必须实现
java.lang.reflect.InvocathinHandler
接口;如代码所示,使用bind方法完成第一步即建立代理对象和真实对象的关系;然后实现代理逻辑的方法即invoke()
方法
测试代理对象
java
package com.ssm.proxy;
import com.ssm.proxy.impl.HelloWorldImpl;
import com.ssm.proxy.impl.JDKProxyExample;
import org.junit.Test;
/**
* JDK动态代理测试类
*/
public class JDKProxyTest {
/**
* 测试使用JDK动态代理创建代理对象并调用方法
*/
@Test
public void testJDKProxy() {
// 创建JDK代理示例实例
JDKProxyExample jdkProxyExample = new JDKProxyExample();
// 绑定真实对象并生成代理对象
HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImpl());
// 通过代理对象调用方法
proxy.sayHelloWorld();
}
}
执行结果如下
bash
before
Hello World!
after
CGLIB动态代理
xml
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
真实对象
java
package com.ssm.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 反射服务实现类
*/
public class ReflectServiceImpl{
/**
* 向指定名字的人打招呼
*
* @param name 人的名字
* @return
*/
public String sayHello(String name)
{
System.out.println( "Hello"+name);
return name;
}
/**
* 获取ReflectServiceImpl类的实例
* 通过反射获取无参构造函数创建实例
* @return 返回ReflectServiceImpl类的实例
*/
public static ReflectServiceImpl getInstance(){
ReflectServiceImpl object = null;
try {
//通过反射获取类的无参构造函数
Constructor<ReflectServiceImpl> constructor = ReflectServiceImpl.class.getConstructor();
//通过构造函数创建实例
object = constructor.newInstance();
}catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException| InvocationTargetException e){
//捕获反射过程中可能抛出的异常
e.printStackTrace();
}
return object;
}
}
代理对象
java
package com.ssm.proxy.impl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Cglib代理示例类,实现了MethodInterceptor接口。
* 用于通过Cglib动态生成代理对象。
*/
public class CglibProxyExample implements MethodInterceptor {
/**
* 获取代理对象。
* @param cls 要代理的类的Class对象
* @return 生成的代理对象
*/
public Object getProxy(Class cls) {
Enhancer enhancer = new Enhancer(); // 创建Enhancer对象,用于配置代理对象
enhancer.setSuperclass(cls); // 设置代理对象的父类为cls
enhancer.setCallback(this); // 设置回调方法为当前对象
return enhancer.create(); // 创建并返回代理对象
}
/**
* 当调用代理对象的方法时,会执行此方法。
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法参数
* @param methodProxy 方法代理
* @return 方法返回值
* @throws Throwable 异常
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)throws Throwable {
// 在方法执行前打印信息
System.out.println("before method " + method.getName());
Object result = methodProxy.invokeSuper(proxy, args); // CGLIB反射调用真实对象方法
// 在方法执行后打印信息
System.out.println("after method " + method.getName());
return result; // 返回方法结果
}
}
测试代理对象
java
package com.ssm.proxy;
import com.ssm.proxy.impl.CglibProxyExample;
import com.ssm.reflect.ReflectServiceImpl;
import org.junit.Test;
/**
* CGLIB代理测试类
* 用于测试CGLIB动态代理的功能
*/
public class CGLIBProxyTest {
/**
* 测试CGLIB代理方法
* 通过CglibProxyExample创建ReflectServiceImpl的代理实例,
* 然后调用代理实例的方法进行测试
*/
@Test
public void testCGLIBProxy() {
// 创建CglibProxyExample实例
CglibProxyExample cpe = new CglibProxyExample();
// 通过CglibProxyExample获取ReflectServiceImpl类的代理实例
ReflectServiceImpl obj = (ReflectServiceImpl) cpe.getProxy(ReflectServiceImpl.class);
// 调用代理实例的方法,并传入参数"CGLIB"
obj.sayHello("CGLIB");
}
}
拦截器
通常动态代理理解起来较为复杂,通常会设计一个拦截器接口供工程师使用,使用者只需要知道拦截器接口的方法、含义和作用即可,无需知道动态代理的实现过程
java
package com.ssm.interceptor;
/**
* 描述了拦截器需要实现的接口。
* 拦截器用于在指定的方法执行前、执行后或环绕执行过程中进行额外的操作。
*/
public interface Interceptor {
/**
* 在目标方法执行前执行的方法。
*
* @param proxy 代理对象,即被拦截对象的代理。
* @param target 目标对象,即被拦截的方法所在的对象。
* @param method 被拦截的方法。
* @param args 被拦截方法的参数数组。
* @return 如果返回false,则阻止目标方法的执行;返回true则继续执行目标方法。
*/
public boolean before(
Object proxy,
Object target,
Method method,
Object[] args
);
/**
* 环绕目标方法执行的方法,可以在方法执行前、执行后、抛出异常时进行操作。
*
* @param proxy 代理对象,即被拦截对象的代理。
* @param target 目标对象,即被拦截的方法所在的对象。
* @param method 被拦截的方法。
* @param args 被拦截方法的参数数组。
*/
public void around(
Object proxy,
Object target,
Method method,
Object[] args
);
/**
* 在目标方法执行后执行的方法。
*
* @param proxy 代理对象,即被拦截对象的代理。
* @param target 目标对象,即被拦截的方法所在的对象。
* @param method 被拦截的方法。
* @param args 被拦截方法的参数数组。
*/
public void after(
Object proxy,
Object target,
Method method,
Object[] args
);
}
java
package com.ssm.interceptor.impl;
import com.ssm.interceptor.Interceptor;
import java.lang.reflect.Method;
/**
* MyInterceptor 类实现了 Interceptor 接口,
* 用于拦截器的实现,提供 before、after 和 around 方法。
*/
public class MyInterceptor implements Interceptor {
/**
* 在目标方法执行前执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
* @return 返回 boolean 值,通常用于决定是否继续执行目标方法
*/
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("before");
return false; // 默认返回false,表示不继续执行目标方法
}
/**
* 在目标方法执行后执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("after");
}
/**
* 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("around");
}
}
将这些方法植入到JDK动态代理对应逻辑内
java
package com.ssm.interceptor.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import com.ssm.interceptor.Interceptor;
/**
* 使用JDK动态代理实现的拦截器处理类,用于生成目标对象的代理实例。
*/
public class InterceptorJdkProxy implements InvocationHandler {
private Object target; // 目标对象,即需要被拦截的对象
private String interceptorClass = null; // 拦截器类的全限定名
/**
* 构造函数,初始化目标对象和拦截器类。
*
* @param target 目标对象
* @param interceptorClass 拦截器类的全限定名
*/
public InterceptorJdkProxy(Object target, String interceptorClass) {
this.target = target;
this.interceptorClass = interceptorClass;
}
/**
* 绑定目标对象和拦截器,返回代理对象。
*
* @param target 目标对象
* @param interceptorClass 拦截器类的全限定名
* @return 代理对象
*/
public static Object bind(Object target, String interceptorClass){
// 通过动态代理生成目标对象的代理实例
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InterceptorJdkProxy(target, interceptorClass));
}
/**
* 当调用代理对象的方法时,实际执行此方法。
*
* @param proxy 代理对象
* @param method 被调用的方法
* @param args 方法参数
* @return 方法返回值
* @throws Throwable 方法执行中抛出的异常
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(interceptorClass == null) {
// 如果设置了拦截器,则先执行拦截器的逻辑
// 没有设置拦截器,直接调用目标方法
return method.invoke(target, args);
}
Object result = null;
// 通过反射实例化拦截器
Interceptor interceptor = (Interceptor)Class.forName(interceptorClass).newInstance();
// 调用拦截器前置方法
if(interceptor.before(proxy, target, method, args)) {
// 如果前置方法返回true,执行目标方法
result = method.invoke(target, args);
}else { // 如果前置方法返回false,执行around方法
interceptor.around(proxy, target, method, args);
}
// 调用拦截器后置方法
interceptor.after(proxy, target, method, args);
return result;
}
}
java
package com.ssm.interceptor;
import com.ssm.interceptor.impl.InterceptorJdkProxy;
import com.ssm.proxy.HelloWorld;
import com.ssm.proxy.impl.HelloWorldImpl;
import org.junit.Test;
/**
* InterceptorJdkProxy的测试类
* 用于测试使用JDK动态代理实现的拦截器功能
*/
public class InterceptorJdkProxyTest {
/**
* 测试拦截器功能
* 通过InterceptorJdkProxy为HelloWorldImpl实例绑定拦截器MyInterceptor,
* 然后调用代理对象的sayHelloWorld方法。
*/
@Test
public void testInterceptor() {
// 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), "com.ssm.interceptor.impl.MyInterceptor");
// 调用代理类的方法,会触发拦截器的逻辑
proxy.sayHelloWorld();
}
}
执行结果如下
bash
反射方法前逻辑
取代了被代理对象的方法
反射方法后逻辑
Process finished with exit code 0
责任链模式
当一个对象在一个链条上被多个拦截器拦截处理(拦截器也可以选择不拦截处理)时,这样的设计模式就成为责任链模式,它适用于一个对象在多个角色中传递的场景,例如一个审批流,一个工程师请假一周,提交了审批单,需要通过3级审批,每一级都有拦截审批或者修改的审批的动作,这就需要三个拦截器,并在它们之间传递请假申请单; 而如多第一级审批修改了审批单,从而影响了后面的审批,后面的审批都要根据前面的结果进行,这个时候就需要考虑用层层代理来实现,也就是后一步的代理是基于前一步代理基础上生成的
定义三个拦截器,然后还是使用之前的JDK动态代理进行绑定和代理逻辑实现进行测试
java
package com.ssm.interceptor.impl;
import com.ssm.interceptor.Interceptor;
import java.lang.reflect.Method;
public class MyInterceptorI implements Interceptor {
/**
* 在目标方法执行前执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
* @return 返回 boolean 值,通常用于决定是否继续执行目标方法
*/
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorI反射方法前逻辑");
return false; // 不反射被代理对象原有方法
}
/**
* 在目标方法执行后执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorI反射方法后逻辑");
}
/**
* 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorI取代了被代理对象的方法");
}
}
java
package com.ssm.interceptor.impl;
import com.ssm.interceptor.Interceptor;
import java.lang.reflect.Method;
public class MyInterceptorII implements Interceptor {
/**
* 在目标方法执行前执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
* @return 返回 boolean 值,通常用于决定是否继续执行目标方法
*/
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorII反射方法前逻辑");
return false; // 不反射被代理对象原有方法
}
/**
* 在目标方法执行后执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorII反射方法后逻辑");
}
/**
* 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorII取代了被代理对象的方法");
}
}
java
package com.ssm.interceptor.impl;
import com.ssm.interceptor.Interceptor;
import java.lang.reflect.Method;
public class MyInterceptorIII implements Interceptor {
/**
* 在目标方法执行前执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
* @return 返回 boolean 值,通常用于决定是否继续执行目标方法
*/
@Override
public boolean before(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorIII反射方法前逻辑");
return false; // 不反射被代理对象原有方法
}
/**
* 在目标方法执行后执行的方法。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void after(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorIII反射方法后逻辑");
}
/**
* 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
* @param proxy 代理对象
* @param target 目标对象
* @param method 目标方法
* @param args 方法参数数组
*/
@Override
public void around(Object proxy, Object target, Method method, Object[] args) {
System.out.println("MyInterceptorIII取代了被代理对象的方法");
}
}
java
package com.ssm.interceptor;
import com.ssm.interceptor.impl.InterceptorJdkProxy;
import com.ssm.proxy.HelloWorld;
import com.ssm.proxy.impl.HelloWorldImpl;
import org.junit.Test;
/**
* InterceptorJdkProxy的测试类
* 用于测试使用JDK动态代理实现的拦截器功能
*/
public class ChainTest {
/**
* 测试拦截器功能
* 通过InterceptorJdkProxy为HelloWorldImpl实例绑定拦截器MyInterceptor,
* 然后调用代理对象的sayHelloWorld方法。
*/
@Test
public void testInterceptorChain() {
String packageName = "com.ssm.interceptor.impl.";
// 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), packageName+"MyInterceptorI");
// 调用代理类的方法,会触发拦截器的逻辑
proxy1.sayHelloWorld();
// 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), packageName+"MyInterceptorII");
// 调用代理类的方法,会触发拦截器的逻辑
proxy2.sayHelloWorld();
// 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
HelloWorld proxy3 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), packageName+"MyInterceptorIII");
// 调用代理类的方法,会触发拦截器的逻辑
proxy3.sayHelloWorld();
}
}
执行结果如下
bash
MyInterceptorI反射方法前逻辑
MyInterceptorI取代了被代理对象的方法
MyInterceptorI反射方法后逻辑
MyInterceptorII反射方法前逻辑
MyInterceptorII取代了被代理对象的方法
MyInterceptorII反射方法后逻辑
MyInterceptorIII反射方法前逻辑
MyInterceptorIII取代了被代理对象的方法
MyInterceptorIII反射方法后逻辑
Process finished with exit code 0
观察者模式
观察者模式又称为发布订阅模式,是对象的行为模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听被观察者的状态,当被观察这得状态发生了变化,会通知所有观察者自动处理各自的逻辑
java
package com.ssm.observer;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
public class ProductList extends Observable {
private List<String> productList = null; //产品列表
private static ProductList productListInstance = null; //类唯一实例
/**
* ProductList的私有构造方法。
* 由于该方法被设置为私有,外部无法直接通过new关键字创建ProductList的实例。
* 这种设计通常用于不允许外部直接实例化对象的类,或者该类仅作为工具类存在,不需实例化。
*/
private ProductList() { // 构造方法私有化,防止外部直接实例化
}
/**
* 获取ProductList的单例实例。
* 该方法采用懒汉式单例模式,即第一次使用时才创建实例。
* 实例在创建时会初始化一个空的产品列表,确保后续可以安全使用。
*
* @return 返回ProductList的单例实例。
*/
private static ProductList getInstance() {
if (productListInstance == null) {
productListInstance = new ProductList();
productListInstance.productList = new ArrayList<>();
}
return productListInstance;
}
/**
* 向产品列表观察者模式中添加一个观察者。
* @param observer 要添加的观察者对象,它必须实现Observer接口。
*/
public void addProductListObserver(Observer observer) {
this.addObserver(observer);
}
/**
* 向产品列表中添加一个新产品,并通知所有观察者。
* @param product 要添加到产品列表的新产品名称。
*/
public void addProduct(String product) {
productList.add(product); // 将新产品添加到产品列表中
this.setChanged(); // 标记产品列表为已更改,通知观察者被观察者变化,触发观察者行为
this.notifyObservers(product); // 通知所有观察者产品列表已更改,传递新产品名称作为更新信息
}
}
java
package com.ssm.observer;
import java.util.Observer;
import java.util.Observable;
/**
* XObserver类实现了Observer接口,用于观察ProductList对象的变化。
*/
public class XObserver implements Observer {
/**
* 当被观察的对象状态发生变化时,此方法会被调用。
*
* @param o 发生变化的Observable对象,这里被强制转换为ProductList类型。
* @param product Observable对象状态变化的具体内容,这里被强制转换为String类型。
*/
@Override
public void update(Observable o, Object product) {
ProductList productList = (ProductList)o; // 将Observable对象转换为ProductList类型
String newProduct = (String)product; // 将变化的内容转换为String类型
System.out.println("XObserver: " + newProduct); // 打印接收到的产品信息
}
}
java
/**
* YObserver类实现了Observer接口,用于观察ProductList对象的变动。
*/
package com.ssm.observer;
import java.util.Observer;
import java.util.Observable;
public class YObserver implements Observer {
/**
* 当被观察的对象发生变动时,此方法会被调用。
* @param o 发生变动的Observable对象。
* @param product 观察到的变动的具体内容。
*/
@Override
public void update(Observable o, Object product) {
// 将Observable对象转换为ProductList类型,将变动内容转换为String类型
ProductList productList = (ProductList)o;
String newProduct = (String)product;
// 打印接收到的产品信息
System.out.println("YObserver: " + newProduct);
}
}
java
package com.ssm.observer;
import org.junit.Test;
/**
* 观察者模式测试类
*/
public class ObserverTest {
/**
* 测试观察者模式的功能
* 无参数
* 无返回值
*/
@Test
public void testObserver(){
// 获取ProductList的实例
ProductList observable = ProductList.getInstance();
// 创建XObserver实例
XObserver xObserver = new XObserver();
// 创建YObserver实例
YObserver yObserver = new YObserver();
// 添加观察者
observable.addObserver(xObserver);
observable.addObserver(yObserver);
// 添加产品到产品列表,触发观察者的更新
observable.addProduct("product1");
}
}
执行测试结果
bash
YObserver: product1
XObserver: product1
Process finished with exit code 0
这也是解决大量if判断的一个好的方式
普通工厂模式和抽象工厂模式
对于需要初始化一个对象而言,有一个工厂逻辑上存在实际上也存在,只需要满足它的接口规范,便可以通过工厂去初始化(生产)一个新的对象出来,这就是普通工厂的思维
java
// 定义产品接口
interface Product {
void produce();
}
// 具体产品A
class ConcreteProductA implements Product {
@Override
public void produce() {
System.out.println("Producing Concrete Product A...");
}
}
// 具体产品B
class ConcreteProductB implements Product {
@Override
public void produce() {
System.out.println("Producing Concrete Product B...");
}
}
// 工厂类
class ProductFactory {
/**
* 根据传入的产品类型字符串返回对应的具体产品实例
*
* @param type 产品类型字符串,如"A"或"B"
* @return 返回对应的具体产品实例
* @throws IllegalArgumentException 当传入无效的产品类型时抛出异常
*/
public static Product createProduct(String type) throws IllegalArgumentException {
if ("A".equals(type)) {
return new ConcreteProductA();
} else if ("B".equals(type)) {
return new ConcreteProductB();
} else {
throw new IllegalArgumentException("Invalid product type: " + type);
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 使用工厂方法创建并生产产品A
Product productA = ProductFactory.createProduct("A");
productA.produce();
// 使用工厂方法创建并生产产品B
Product productB = ProductFactory.createProduct("B");
productB.produce();
}
}
在这个例子中,我们定义了一个产品接口Product以及两个实现了该接口的 concrete products:ConcreteProductA和ConcreteProductB。接着,我们创建了一个ProductFactory工厂类,它提供了一个静态方法createProduct(),根据传入的产品类型字符串返回对应的具体产品实例。客户端代码Client通过调用工厂方法来创建并操作产品,无需直接关心具体产品的创建细节,从而实现了对产品对象的解耦。这就是普通工厂设计模式的应用
普通工厂思维解决了一类对象的构建问题,但有时候往往类别又很多,而不是一类,因此需要更高度的抽象一层,而这种情况下对于需要初始化对象而言只需要知道一个逻辑上存在的工厂存在,而无需关心真实的工厂有多少种如何区分的怎么找到他,这就是抽象工厂思维
java
// 定义产品接口
interface Computer {
void assemble();
}
// 具体产品:MacComputer
class MacComputer implements Computer {
@Override
public void assemble() {
System.out.println("Assembling Mac Computer...");
}
}
// 具体产品:WindowsComputer
class WindowsComputer implements Computer {
@Override
public void assemble() {
System.out.println("Assembling Windows Computer...");
}
}
// 抽象工厂接口
interface ComputerFactory {
Computer createComputer();
}
// 具体工厂:MacFactory
class MacFactory implements ComputerFactory {
@Override
public Computer createComputer() {
return new MacComputer();
}
}
// 具体工厂:WindowsFactory
class WindowsFactory implements ComputerFactory {
@Override
public Computer createComputer() {
return new WindowsComputer();
}
}
//抽象工厂
package com.ssm.factory;
public class ABProductFactory implements ComputerFactory{
@Override
public Computer createComputer(String productNo) {
ComputerFactory factory=null;
if(productNo == "mac"){
factory= (ComputerFactory) new MacFactory();
}
else if(productNo =="windows"){
factory= (ComputerFactory) new WindowsFactory();
}
else if(productNo != null){
factory= (ComputerFactory) new LinuxFactory();
}
return null;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 使用MacFactory创建并组装Mac电脑
ABProductFactory abProductFactory = new ABProductFactory();
ComputerFactory macFactory = (ComputerFactory) abProductFactory.createComputer("mac");
macFactory.createComputer("mac");
// 使用WindowsFactory创建并组装Windows电脑
ComputerFactory windowsFactory = (ComputerFactory) abProductFactory.createComputer("windows");
windowsFactory.createComputer("windows");
}
}
建造者模式
建造者模式属于对象的构建模式,可以将一个产品的内部属性与产品的生产过程分开来,从而使一个建造过程生成具有不同内部表象的产品;通过一个配置类对构建对象的步骤和参数进行统筹,然后将信息交给构建器来完成对象的构建,就是该模式的本质
java
// 定义Car类,表示汽车
class Car {
private String engine;
private String transmission;
private String bodyType;
private int seats;
public String getEngine() {
return engine;
}
public String getTransmission() {
return transmission;
}
public String getBodyType() {
return bodyType;
}
public int getSeats() {
return seats;
}
protected void setEngine(String engine) {
this.engine = engine;
}
protected void setTransmission(String transmission) {
this.transmission = transmission;
}
protected void setBodyType(String bodyType) {
this.bodyType = bodyType;
}
protected void setSeats(int seats) {
this.seats = seats;
}
@Override
public String toString() {
return "Car{" +
"engine='" + engine + '\'' +
", transmission='" + transmission + '\'' +
", bodyType='" + bodyType + '\'' +
", seats=" + seats +
'}';
}
}
// 定义抽象的CarBuilder接口
interface CarBuilder {
void setEngine(String engine);
void setTransmission(String transmission);
void setBodyType(String bodyType);
void setSeats(int seats);
Car build();
}
// 具体的CarBuilder实现:SportsCarBuilder
class SportsCarBuilder implements CarBuilder {
private Car sportsCar = new Car();
@Override
public void setEngine(String engine) {
sportsCar.setEngine(engine);
}
@Override
public void setTransmission(String transmission) {
sportsCar.setTransmission(transmission);
}
@Override
public void setBodyType(String bodyType) {
sportsCar.setBodyType(bodyType);
}
@Override
public void setSeats(int seats) {
sportsCar.setSeats(seats);
}
@Override
public Car build() {
return sportsCar;
}
}
// 具体的CarBuilder实现:SUVBuilder
class SUVBuilder implements CarBuilder {
private Car suv = new Car();
@Override
public void setEngine(String engine) {
suv.setEngine(engine);
}
@Override
public void setTransmission(String transmission) {
suv.setTransmission(transmission);
}
@Override
public void setBodyType(String bodyType) {
suv.setBodyType(bodyType);
}
@Override
public void setSeats(int seats) {
suv.setSeats(seats);
}
@Override
public Car build() {
return suv;
}
}
// 负责协调建造过程的CarDirector类
class CarDirector {
public Car construct(CarBuilder builder) {
builder.setEngine("V6");
builder.setTransmission("Automatic");
builder.setBodyType("Sports");
builder.setSeats(4);
return builder.build();
}
}
// 主程序,演示如何使用建造者模式构建汽车
public class BuilderPatternDemo {
public static void main(String[] args) {
CarDirector director = new CarDirector();
CarBuilder sportsCarBuilder = new SportsCarBuilder();
Car sportsCar = director.construct(sportsCarBuilder);
System.out.println("Built Sports Car: " + sportsCar);
CarBuilder suvBuilder = new SUVBuilder();
Car suv = director.construct(suvBuilder);
System.out.println("Built SUV: " + suv);
}
}