1.Java反射技术
要学习Java设计模式就先了解Java的反射技术,这是十分重要的,这样就可以增加Java的可配置性。
1.1、什么是Java反射技术
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。利用反射机制,Java程序可以加载一个运行时才得知名称的class。
1.2通过反射构建对象
1.2.1项目结构
首先,创建一个被反射的User类
package 反射;
public class User {
public void sayHello()
{
System.out.println("你好反射");
}
}
然后,通过反射去构建它
package getClass;
import 反射.User;
public class Reflex {
public User getInstance()
{
User user=null;
try {
user=(User) Class.forName("反射.User").newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return user;
}
}
Class.forName(“类的全限定名”),也就是要找到它的位置在哪,然后newInstance来初始化它,这样就构建了一个类对象。
然后测试
package test;
import org.junit.Test;
import getClass.Reflex;
public class TestOne {
@Test
public void test()
{
try {
Reflex reflex=(Reflex) Class.forName("getClass.Reflex").newInstance();
reflex.getInstance().sayHello();;
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
这里同样用的是反射找到了Reflex,然后初始化,调用其方法得到user类对象,然后调用user方法。如果是要反射带有参数的构造方法的类,则需要
用Class.forName(“类的全限定名”).getConstructor(String.class(参数类型)).newInstance(“参数”),有多少个参数就写多少个参数。
2.反射方法
同样的方法也是可以反射的,上面我们是通过反射得到类对象后调用其方法,现在直接可以用反射完成同样的事情,User类不变,现在不用Reflex类了
直接写test类。
package getClass;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.junit.Test;
import 反射.User;
public class Reflect2 {
@Test
public void Test() throws Exception
{
User user=(User) Class.forName("反射.User").newInstance();
Method method=user.getClass().getMethod("sayHello");
Object ob=method.invoke(user);
}
}
同样的,这里先反射构建出了user对象,然后在通过getMethod(“方法名”,“参数类型”),最后调用invoke方法执行方法,注意这里不能直接写成user.getClass().getMethod().invoke(),除非你已经导入了java.lang.reflect.Method。
2.动态代理模式和责任链模式
2.1什么是动态代理
举个例子就是如果一个客户想要开发一款软件,他去软件公司是会直接找程序员谈吗,而是去找商务谈,这样的话商务和程序员的关系就是代理和被代理的关系,这样的意义就是,可以帮被代理对象被访问前添加一些功能,在访问后也同样加入相应逻辑可以添加一些功能,而被代理对象程序员只负责写代码就行了。
动态代理主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等,实现解耦。
2.2如何实现动态代理
我们需要在调用者和调用对象之前产生一个代理对象,代理对象和调用对象需要建立代理关系,然后实现代理对象的代理逻辑方法。
因为JDK产生动态代理对象的方法必须要有一个接口,所以先定义一个接口
package interfaceOne;
public interface Hello {
public void sayHello();
}
然后Hello实现类
package imp;
import interfaceOne.Hello;
public class HelloImp implements Hello{
public void sayHello()
{
System.out.println("你好动态代理");
}
}
代理对象的实现
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxy implements InvocationHandler{
//被代理的对象,这里也就是HelloImp对象,
//这里写成Object是因为什么类型都可以传进来
private Object target=null;
public Object bind(Object target)
{
this.target=target;
/*target.getClass().getClassLoader:target的类加载器
target.getClass().getInterfaces():target实现的接口
this:表示当前对象,这个参数定义实现方法逻辑的代理类,
指的就是下面的实现了InvocationHandler接口的invoke方法
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
/*proxy:代理对象
Method:跟之前反射的Method是一样的,这样就可以调用什么方法就实现该逻辑
args:当前调用方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("在调用被代理对象之前");
Object obj=method.invoke(target, args);
System.out.println("在调用被代理对象后");
return obj;
}
}
测试
package test;
import org.junit.Test;
import imp.HelloImp;
import interfaceOne.Hello;
import proxy.JdkProxy;
public class TestThree {
@Test
public void Test()
{
JdkProxy jdkProxy=new JdkProxy();
Hello proxy=(Hello) jdkProxy.bind(new HelloImp());//生成代理对象
proxy.sayHello();
}
}
2.3拦截器
拦截器给我启发挺大的,根据上面学的动态代理,可以自己写拦截器了,我们可以设计一个拦截器接口然后可以给别人使用,他只需要知道拦截器的方法,含义和作用就可以了。
定义接口
package interceptor;
import java.lang.reflect.Method;
public interface Interceptor {
public boolean before(Object proxy, Method method, Object[] args);
public boolean arround(Object proxy, Method method, Object[] args);
public boolean after(Object proxy, Method method, Object[] args);
}
被代理对象接口
package pojoInterface;
public interface SayHello {
public void Say(String name);
}
被代理对象
package pojoImp;
import pojoInterface.SayHello;
public class SayHelloImp implements SayHello{
@Override
public void Say(String name) {
// TODO Auto-generated method stub
System.out.println("name:"+name);
}
}
动态代理对象加入拦截器
package interceptorProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import interceptor.Interceptor;
public class InterceptorProxy implements InvocationHandler {
private Object target;//被代理对象
private String interceptorImp;//拦截器,这里我们只需要传入我们写的拦截器实现类的路径就可以了;
public InterceptorProxy(Object target,String interceptorImp)//构造方法传入参数
{
this.target=target;
this.interceptorImp=interceptorImp;
}
public static Object bind(Object target,String interceptorImp,Object arrays)
{
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InterceptorProxy(target,interceptorImp));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
if(interceptorImp==null)
{
return method.invoke(target, args);
}
Object result=null;
//通过反射生成拦截器
Interceptor interceptor=(Interceptor) Class.forName(interceptorImp).newInstance();
if(interceptor.before(proxy,method,args))//如果实现类的返回值是true,就执行before方法说明开发者想要执本来的方法
{
System.out.println("test");
result=method.invoke(target, args);
}
else
{
interceptor.arround(proxy,method,args);//执行替代方法也就是说开发者觉得不能执行原方法
}
interceptor.after(proxy, method, args);
return result;
}
}
下面只需要写接口实现类就可以实现拦截器功能了
拦截器实现
package interceptorImp;
import java.lang.reflect.Method;
import interceptor.Interceptor;
public class InterceptorImp implements Interceptor {
@Override
public boolean before(Object proxy, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("反射方法前逻辑");
return false;
}
@Override
public boolean arround(Object proxy, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("我觉得不行,我要替换掉你");
return false;
}
@Override
public boolean after(Object proxy, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("好了结束");
return false;
}
}
测试
package interceptorTest;
import org.junit.Test;
import interceptorProxy.InterceptorProxy;
import pojoImp.SayHelloImp;
import pojoInterface.SayHello;
public class TestOne {
@Test
public void test()
{
String name="123";
SayHello sayHello=(SayHello) InterceptorProxy.bind(new SayHelloImp(),"interceptorImp.InterceptorImp",name);
sayHello.Say(name);
}
}
拦截器总结,主要还是动态代理的知识,如果我们了解动态代理 ,可以在其中的invoke方法写入我们想要的代理逻辑,我们只需要在代理类的实现类中传入我们写的接口,里面有我们的写入方法名,根据其他人或者自己写的实现类返回值就可以实现相关方法。开发人员只需要按照自己想要执行的方法写实现类就可以实现相关方法了,耦合度大大降低,减少代码量。
责任链模式
有了上面的拦截器的知识,责任链就简单了,就是多了几个拦截器,关键点是把上一个产生的代理对象当作被代理对象继续传入生成代理对象
拦截器二
package interceptorImp;
import java.lang.reflect.Method;
import interceptor.Interceptor;
public class InterceptorImp2 implements Interceptor {
@Override
public boolean before(Object proxy, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("反射方法前逻辑2");
return true;
}
@Override
public boolean arround(Object proxy, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("我觉得不行,我要替换掉你");
return false;
}
@Override
public boolean after(Object proxy, Method method, Object[] args) {
// TODO Auto-generated method stub
System.out.println("好了结束2");
return false;
}
}
测试
package interceptorTest;
import org.junit.Test;
import interceptorProxy.InterceptorProxy;
import pojoImp.SayHelloImp;
import pojoInterface.SayHello;
public class TestOne {
@Test
public void test()
{
String name="123";
SayHello sayHello=(SayHello) InterceptorProxy.bind(new SayHelloImp(),"interceptorImp.InterceptorImp");
SayHello sayHello2=(SayHello) InterceptorProxy.bind(sayHello,"interceptorImp.InterceptorImp2");//这里将上面的代理对象传入
sayHello2.Say(name);
}
}
那么责任链模式的优点就是可以加入新的拦截器,增加拦截逻辑。before执行顺序为从最后一个拦截器到第一个拦截器,after则为第一个拦截器到最后一个拦截器