黑马程序员 动态代理学习笔记二,黑马学习笔记
黑马程序员 动态代理学习笔记二,黑马学习笔记
----------android培训、java培训、java学习型技术博客、期待与您交流!----------
创建代理:
InvocationHandler接口
创建实现Collection接口的动态类和查看其名称,分析Proxy.getProxyClass方法的各个参数
创建动态类的实例对象
1)用反射获得构造方法
2)编写一个简单的InvocationHandler类
3)调用构造方法创建动态类的实例对象,并编写的InvocationHandler类的实例对象穿进去
让JVM创建动态类及其实例对象,需要给它提供哪些信息?
1)生成的类中有哪些方法,通过让其实现哪些接口的方式进行告知
2)产生的类字节码必须有一个关联的类加载器对象
3)生成的类中的方法的代码是怎样的,也得由我们提供,把我们的代码写在一个约好的接口对象
InvocationHandler的运行原理
创建某一接口 MyInterface 的代理:
1)
InvocationHandler handler = new MyInvocationHandler(...);
代理实例调用处理程序实现的接口,对代理实例调用方法时,将对方法调用进行编码并将其指
派到它的调用处理程序的 invoke 方法
Class proxyClass = Proxy.getProxyClass(
MyInterface.class.getClassLoader(), new Class[] { MyInterface .class });
得到接口代理类的类加载器,要接口数组(因为可能要加载的不是一个接口)
MyInterface myint = (MyInterface ) proxyClass.getConstructor(new Class[] {
InvocationHandler.class }).newInstance(new Object[] { handler });
创建实例对象
2)
MyInterface myint = (MyInterface) Proxy.newProxyInstance(
MyInterface .class.getClassLoader(),接口的类加载器
new Class[] { MyInterface .class },要实现动态代理类的接口
new InvocationHandler(){
ArrayList target=new ArrayList();
public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
Object retVal=method.invoke(target,args);
return target;此时target是Object类型,传入什么类型,我就是什么类型
}
}
);匿名内部类
为了增强框架功能,封装成一个对象
objProxy.add("abc");方法,涉及到的三要素:objProxy对象、add方法、"abc"参数
objProxy对象——>Object proxy
add方法——>Method methods,继承Object只有hashCode,equals,toString这三个方法交给
handler
"abc"参数——>Object[] args
Class proxy${
add(Object obj){
return handler.invoke(Object proxy,Method method,Object[] args);
}
}
三、简易Spring,对代理类进行封装
1)advice建议、协议
public interface Advice{
void beforMethod(Method method);
void afterMethod(Method method);
}
2)myAdvice用户自己定义的advice,和协议相符合,以便调用代理
public class myAdvice{
public void beforMethod(Method method){
定义自己的功能,或是广告
}
public void afterMethod(Method method){
定义自己的功能,或是广告
}
}
3)ProxyFactoryBean实现代理功能,进行的封装
public class ProxyFactoryBean {
private Advice advice;
private Object target;
code…
创建代理
public Object getProxy() {
}
}
4)BeanFactory通过读取Properties,获取要代理的类的相关信息
public class BeanFactory {
Properties props = new Properties();
public BeanFactory(InputStream ips){
try {
props.load(ips);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
其实,通过认真学习张老师的视频教程,不难发现,动态代理的核心代码要素一个是代理的接口,该接口声明了代理的核心功能,另一个是java.lang.reflect.InvocationHandler接口,该接口的存在,主要是利用其中的public Object invoke(Objectproxy,Method method,Object[] args)函数的实现来实现代理接口中的方法,在调用被代理的接口中的方法时,该invoke方法就会被调用,且代理对象、所调用方法的Method对象及实际参数都会作为invoke方法的参数,例如:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy {
public static void main(String[] args) {
Action action = (Action)Proxy.newProxyInstance(
//代理接口的类加载器,或者某个类的加载器
Action.class.getClassLoader(),
//代理类接口的Class
new Class[]{Action.class},
//InvocationHandler接口的实现
new MyInvocationHandler()
);
/*每次调用代理时,都会调用MyInvocationHandler中的
* public Object invoke(Object proxy,Method method,Object[] args)这个方法
* 该方法对客户是半透明的,换句话说,就是客户知道的其实现了自己的要求,但是其中的其他业务逻辑(比如广告啊什么的),
* 用户是事先不知道的,我把这种情况称为半透明。*/
/*调用代理的smile()方法实现Man类的smile()方法时,MyInvocationHandler中的invoke方法里的内容
* 都会执行,那么就自然会执行System.out.println("我是"+man.getName()+",我为自己代言");这条语句
* 从而打印“我是陈欧,我为自己代言”*/
action.smile();
action.speak();
}
}
interface Action{
void speak();
void run();
void smile();
}
class MyInvocationHandler implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/*以下是广告阶段,哈哈...
* 其实,这就是AOP中的的那个切面
* */
Man man = new Man();
man.setName("陈欧");
System.out.println("我是"+man.getName()+",我为自己代言");
//执行代理对象所要代理的核心方法,这些方法才是客户的需求核心
return method.invoke(man, args);
}
}
class Man implements Action{
private String name;
private int aga;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAga() {
return aga;
}
public void setAga(int aga) {
this.aga = aga;
}
@Override
public void speak(){
System.out.println("man can speak");
}
@Override
public void run() {
System.out.println("man can run");
}
@Override
public void smile() {
System.out.println("man can smile");
}
public void makeMoney(){
System.out.println("赚钱");
}
}
这里,还可以将其封装成一个获得动态代理的方法,如下所示:
Man类同上
public class MyProxy {
public static void main(String[] args) {
Action action = (Action)getProxy(new Man(),new Man());
action.smile();
action.speak();
}
//注意,Man man可以是其他切面逻辑,这里为了简便,就用的是与代理目标target相同的类
public static Object getProxy(final Object target,final Man man){
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Man man = new Man();
man.setName("陈欧");
System.out.println("我是"+man.getName()+",我为自己代言");
//执行代理对象所要代理的核心方法,这些方法才是客户的需求核心
return method.invoke(target, args);
}
});
return proxy;
}
}
总结:动态代理听起来感觉很难,但是学起来确实感觉很有意思。
----------android培训、java培训、java学习型技术博客、期待与您交流!----------
相关文章
- 暂无相关文章
用户点评