重点知识回顾
- 反射机制
- 在运行期间,对于任意类都能知道它的所有属性和方法,对于任意对象都能调用它的属性和方法
- 静态代理
- 通过编写代码完成增强效果,即是通过我们自己编写相关的代码实现增强效果。
java的动态代理过程
我们都知道java动态代理,多数的面试官可能会结合spring aop的代理过程,来对比它和cglib动态代理的区别,二者的区别我是记住了,可是面试官问我java动态代理的实现过程时,我却无法描述清楚,当时脑海里只有InvocationHandler 类,invoke方法,可是具体怎么做的却回答不上来。其实这些知识点并不是我们不会,只是没有特别注意到,心中没有这个概念自然而然的回答不出来。
动态代理过程
- 自定义的接口和实现类(你可以理解为你项目中写的那些service类)
- 自定义自己的InvocationHandler 继承 InvocationHandler 实现 invoke方法,在这里实现代理增强效果,如打开事务,关闭事务等,然后会调用 被代理的类的方法
- 使用Proxy.newProxyInstance 创建代理对象
掌握这几步,结合下面的代码,即使面试官让你用代码写出来,也完全不慌
代码实现:
/**
* 1.服务接口
* */
public interface TestService {
public String doSomething(String param);
}
/**
* 2.实现类
* */
public class TestServiceImpl implements TestService{
@Override
public String doSomething(String param) {
System.out.println("do something in TestServiceImpl : "+param);
return param;
}
}
/**
* 3.自定义InvocationHandler
* 在这里做一些增强效果
* */
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doMyMethodBefore(method.getName());
Object ret = method.invoke(target, args);
doMyMethodAfter(method.getName());
return ret;
}
private void doMyMethodBefore(String name){
System.out.println("在被代理的方法执行之前做一些其他事情:" + name);
}
private void doMyMethodAfter(String name){
System.out.println("在被代理的方法执行之后做一些其他事情:" + name);
}
}
/**
* 4.Proxy.newProxyInstance 创建对象
* */
public class JDKDynamicProxyFactory {
public static Object getProxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new MyInvocationHandler(target));
}
}
测试过程
public static void main(String[] args) {
TestService service = (TestService)JDKDynamicProxyFactory.getProxy(new TestServiceImpl());
service.doSomething("test");
}
测试结果
在被代理的方法执行之前做一些其他事情:doSomething
do something in TestServiceImpl : test
在被代理的方法执行之后做一些其他事情:doSomething
这个时候如果单看这些其实感觉跟静态代理差不多,或者实现看起来还没有静态代理简单,可如果我们有很多服务都通过它来代理,显然要方便的多
比如我这个时候有另外一个service,也想要进行上面的增强效果:
public interface TestService2 {
public void doIt(String msg);
}
public class TestService2Impl implements TestService2{
@Override
public void doIt(String msg) {
System.out.println("do something in TestService2Impl : "+msg);
}
}
测试内容:
public static void main(String[] args) {
TestService service = (TestService)JDKDynamicProxyFactory.getProxy(new TestServiceImpl());
service.doSomething("test");
TestService2 service2 = (TestService2)JDKDynamicProxyFactory.getProxy(new TestService2Impl());
service2.doIt("hello");
}
测试结果
在被代理的方法执行之前做一些其他事情:doSomething
do something in TestServiceImpl : test
在被代理的方法执行之后做一些其他事情:doSomething
在被代理的方法执行之前做一些其他事情:doIt
do something in TestService2Impl : hello
在被代理的方法执行之后做一些其他事情:doIt
扩展知识点 CGLIB 代理
JDK动态代理只能代理实现了接口的类,CGLIB不仅可以代理实现了接口的类,同时还可以代理普通类(未实现接口的类),需要强调的是,CGLIB是通过继承被代理的类来完成代理效果的,所以,如果被代理的类是final的或者它的方法是final则不会起作用