《JavaEE互联网轻量级框架整合开发》读书笔记02

20200304-Java设计模式

一、Java反射技术-反射(Reflection)

Java反射技术应用广泛,能够配置:类的全限定名、方法和参数,完成对象的初始化,反射某些方法
内容:对象构建、反射方法、注解、参数、接口等。
在Java中反射是通过包java.lang.reflect.*实现的。

反射的前提: 已经加载过这个类,就可以通过类名来寻找到这个类的所有相关信息。(一看到蜡笔小新四个字就会在脑子里想到小新的模样,前提是知道小新的模样)
反射机制:通过一个抽象的类名能够在自己记忆(加载类的内存)中找到相匹配的类的具体信息。
1.通过反射构建对象
优点:只要配置就可以生成对象,可以解除程序的耦合度,比较灵活。
缺点:运行比较慢。
2.反射方法
需要先获取方法对象,得到了方法才能去反射。
3.示例

01:反射对象,获取方法
package com.lean.ssm.chapter2.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectServiceImpl {
	public void sayHello(String name) {
		System.out.println("Hello!" + name);
	}

	public Object reflect() {
		ReflectServiceImpl obj = null;
		try {
			obj = (ReflectServiceImpl) Class.forName("com.lean.ssm.chapter2.reflect.ReflectServiceImpl").newInstance();

			Method mm = obj.getClass().getMethod("sayHello", String.class);
			mm.invoke(obj, "zhangs");
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 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 obj;
	}

}

调用:

	public static void main(String[] args) {
		ReflectServiceImpl rr = new ReflectServiceImpl();
		rr.reflect();
	}

结果:
在这里插入图片描述

02:反射对象构造
			Class clazz = Class.forName("com.lean.ssm.reflect.Student");//找到加载过的类

			Class suClazz = clazz.getSuperclass();//取得父类

			System.out.println("father:" + suClazz.getName());

			Class[] ClassInfo = clazz.getInterfaces();//取得接口

			for (Class class1 : ClassInfo) {
				System.out.println("interface:" + class1.getName());
			}
			System.out.println("*************");
			Constructor[] cons = clazz.getConstructors();//获取公有的构造器
			for (Constructor con : cons) {
				System.out.println(con.getName());
				System.out.println("/");
				System.out.println(con.getModifiers());//获取构造器的修饰符 1-public  2-private
			}
			System.out.println("--------------------");			
			Constructor[] cons2 = clazz.getDeclaredConstructors();//获取所有构造器,包括私有
			for (Constructor con : cons2) {
				System.out.println(con.getName());
				System.out.println("/");
				System.out.println(con.getModifiers());
				System.out.println("==============");
				Class[] parm =con.getParameterTypes();//获取构造器的参数列表的参数类型
				for (Class aa : parm) {
					System.out.println("type:"+aa.getName());
				}
			}
			//01
			Student stu = (Student) clazz.newInstance();//创建对象
			System.out.println(stu);
			//02 
			Constructor c = clazz.getConstructor(String.class);
			Student stu2 = (Student)c.newInstance("school");//相当于 Student stu = new Student();
			System.out.println(stu2);
			System.out.println(stu2.school);
			//03 
			Constructor c2 = clazz.getDeclaredConstructor(String.class,int.class);//方法接收参数都是class类型
			c2.setAccessible(true);//解除访问修饰符的限制,可以对私有方法强制调用
			Student stu3 = (Student)c2.newInstance("zhangs",5);
			System.out.println(stu3);
03:反射获取类的全部方法
            Class clazz = Class.forName("com.lean.ssm.reflect.Student");
//			Method[] me = clazz.getMethods();//获取到类的所有的公有方法(含equals等方法)
			Method[] me = clazz.getDeclaredMethods();//获取类的所有方法,包含公有私有(不含equals等方法)
			for (Method method : me) {
				System.out.println(method.getName());
				System.out.println(method.getReturnType());
				System.out.println(method.getModifiers());
				System.out.println("-");
				Class[] cl = method.getParameterTypes();
				if(cl!=null&&cl.length>0) {
					for (Class clzz : cl) {
						System.out.println(clzz);
					}
				}
				System.out.println("***************************");
			}
04:获取类的属性和包
属性:
			Class clazz = Class.forName("com.lean.ssm.reflect.Student");
//			Field[] ff = clazz.getFields();//获取类的公有的属性,包含父类的共有属性
			Field[] ff = clazz.getDeclaredFields();//获取本类的所有的属性,包括私有
			
			for (Field field : ff) {
				System.out.println(field.getModifiers());
				System.out.println(field.getType());
				System.out.println(field.getName());
				
			}
包:
			Package p = clazz.getPackage();//获取类所在的包
			System.out.println(p.getName());

```java
05:通过反射调用类中的指定方法、指定属性
指定方法:
			Class c = Class.forName("com.lean.ssm.reflect.Student");
			
			//注意:下面无论是反射嗲用setInfo方法还是test方法
			//都调用的是obj对象的方法,obj实际上就是student对象
			
			Constructor con = c.getConstructor();//获取无参构造
			Object obj = con.newInstance();//使用无参构造创建对象
			//调用公有方法
			//得到名称是setInfo,参数是String,String的方法
			//方法第一个参数是调用的方法名,第二个是被调用的方法的参数类型
			Method mm = c.getMethod("setInfo", String.class,String.class);
			//调用方法,参数1是需要实例化的对象,后面的参数是调用当前方法的实际参数
			mm.invoke(obj, "nn","ss");
			
			//调用私有方法
			Method m1 = c.getDeclaredMethod("test", String.class);
			m1.setAccessible(true);//解除私有封装下面可以强制调用私有方法
			m1.invoke(obj, "ss");
			
			//调用一个重载方法
			Method m2 = c.getMethod("setInfo", int.class);
			m2.invoke(obj, 5);
			
			//有返回值的方法
			Method m3 = c.getMethod("getSchool");//获取方法名为getSchool并且没有返回值的方法
			String school = (String) m3.invoke(obj);//调用有返回值但是没有参数方法
			System.out.println(school);		
指定属性:
			Class c = Class.forName("com.lean.ssm.reflect.Student");
			//反射创建一个对象
			Constructor con = c.getConstructor();
			Student stu = (Student) con.newInstance();
			//公有的
			Field f = c.getField("school");//获取名称为school的属性
			f.set(stu, "oneschool");//对stu对象的school属性设置值:oneschool
			String str = (String) f.get(stu);//获取stu对象的school属性的值
			System.out.println(str);
			
			//私有属性
			Field f1 = c.getDeclaredField("privatefield");//获取名称为privatefield的属性
			f1.setAccessible(true);
			f1.set(stu, "ol");
			String str1 = (String) f1.get(stu);
			System.out.println(str1);

结论:对象在反射机制下生成后,反射了方法,增强了Java的可配置性和可扩展性,其中SpringIOC就是一个典型的例子。

二、动态代理

1.动态代理(反射的关键应用)
**意义:**生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问。
**理解:**在真实对象访问之前或者之后加入对应逻辑,或者根据其他规则控制是否使用真实对象。
步骤:
(1)代理对象和真实对象建立代理关系
(2)实现代理对象的代理逻辑方法
JDK代理方法:

public interface ItestProxy {
	
	void test1();
	void test2();

}
public class TestProxyImpl implements ItestProxy {

	@Override
	public void test1() {
		System.out.println("执行test1");

	}

	@Override
	public void test2() {
		System.out.println("执行test2");

	}

}
/**
 * 动态代理类
 * @author BMX
 *
 */
public class ProxyDemo implements InvocationHandler {
	Object obj;//被代理的对象
	
	public ProxyDemo(Object obj) {
		this.obj = obj;
	}

	@Override
	public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
		System.out.println(arg1.getName()+"开始执行");
		Object obj1 = arg1.invoke(this.obj, arg2);//执行的是指定代理对象的指定方法
		System.out.println(arg1.getName()+"执行结束");
		return obj1;
	}

}

ItestProxy test = new TestProxyImpl();
		/**
		 * 注意:如果一个对象想要通过Proxy.newProxyInstance方法被代理
		 * 	那么这个对象的类一定要有相应的接口
		 * 	就像本类中的ItestProxy接口和实现类TestProxyImpl一样
		 */
		test.test1();
		test.test2();
		/**
		 * 需求:在执行test1、2方法时,需要加入一些东西
		 * 方法执行前打印开始执行
		 * 方法执行后打印执行完毕
		 * 打印的方法名需要跟当前运行的方法名一致
		 */
		System.out.println("**********************");
		InvocationHandler ih = new ProxyDemo(test);
		/**
		 * Proxy.newProxyInstance(参数1, 参数2, 参数3);
		 * 参数1=动态代理类的对象.getClass().getClassLoader()
		 * 参数2=被代理的对象的接口=test.getClass().getInterfaces()
		 * 参数3=代理对象=ih
		 * 
		 * 返回值:成功被代理后的对象-(test被代理成功之后)
		 * 返回的是object类型,需要根据当时的情况去转换类型
		 */
		ItestProxy t = (ItestProxy) Proxy.newProxyInstance(ih.getClass().getClassLoader(), test.getClass().getInterfaces(), ih);
		t.test1();
		t.test2();

结果
在这里插入图片描述
CGLIB动态代理
优势:不需要提供接口,只需要一个非抽象类就能实现动态代理。
拦截器
程序设计者通常会设计一个拦截器接口供开发者使用,开发者只需要知道拦截器接口的方法、含义和作用即可。

java拦截器实现功能类似于SpringAOP,实现拦截部分方法,一般用于网站登录: 登录进入A页面,未登录进入B页面。
实现方法有两种 :
实现Interceptor 接口 -实现接口需要实现其中所有方法
继承HandlerInterceptorAdapter类-继承抽象类则一般实现preHandle方法即可。

接口:
public interface Interceptor {

	public boolean before(Object proxy,Object target,Method method,Object[] args);
	
	public void around(Object proxy,Object target,Method method,Object[] args);
	
	public void after(Object proxy,Object target,Method method,Object[] args);
	
}
实现类:
public class InterceptorJdkProxy implements InvocationHandler {

	private Object target;//真实对象
	private String interceptorClass=null;//拦截器全限定名
	
	
	public InterceptorJdkProxy(Object target, String interceptorClass) {
		this.target = target;
		this.interceptorClass = interceptorClass;
	}
	/**
	 * 绑定委托对象并返回一个【代理占位】
	 * @param target 真实对象
	 * @return 代理对象【占位】
	 */
	public static Object bind(Object target,String interceptorClass) {
		return Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), 
				new InterceptorJdkProxy(target,interceptorClass)
				);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if(interceptorClass == null) {
			return method.invoke(target, args);
		}
		Object result = null;
		Interceptor inter = (Interceptor) Class.forName(interceptorClass).newInstance();
		if(inter.before(proxy, target, method, args)) {
			result = method.invoke(target, args);
		}else {
			inter.around(proxy, target, method, args);
		}
		inter.after(proxy, target, method, args);
		return result;
	}

}
测试:
main(){
	A proxy = (A) InterceptorJdkProxy.bind(new AImpl(),"拦截器全类名");
	proxy.方法();
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值