JDK动态代理
在开始学习Spring AOP(面向切面编程)的时候,就碰到了jdk动态代理,据说这是实现AOP的底层技术。
于是乎搜罗了以下blog加深学习:
1. http://www.cnblogs.com/luotaoyeah/p/3778183.html
2. http://m.blog.csdn.net/blog/weitry/38460385
3. http://wwyu8901.iteye.com/blog/846919
目前还仅限于会用的程度。。。
比如应用场景: 准备在调用某个方法的前后加上一些log。
方法有3种:
1. 在有源码的前提下,直接在方法前后加上代码;
2. 若无源码,则可以使用继承的方式,重写方法;
3. (推荐)如果该类实现了接口,则采用组合的方式,也实现这个接口,重写方法。
而AOP的实现方式就类似于第3种方法,也是JDK动态代理的实现方式。
所谓的JDK动态代理主要涉及到java.lang.reflect包中的Proxy类和InvocationHandler接口。
1. 通过实现InvocationHandler接口,可以定义实现横切逻辑的方法(比如打log);重写invoke(),从而利用反射机制调用目标类的代码,将横切逻辑和业务逻辑动态编织在一起;
2. Proxy则为InvocationHandler实现类动态创建一个符合某一接口的代理实例。
注意:JDK动态代理依靠接口实现,若某个类没有实现接口,则JDK无法为该类生成代理实例。
具体实例的Code:
User类:
public class User { private String name; private String id; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } }
1. 接口和实现类
public interface UserDAO { public void save(User user); }
public class UserDAOImpl implements UserDAO { @Override public void save(User user) { System.out.println("user is saved"); } }
2. 在执行save()前后加上log,所以使用JDK动态代理。实现InvocationHandler接口 + 利用Proxy生成代理实例:
public class LogIntercepter implements InvocationHandler{ private Object target; public Object getTarget() { return target; } //只需一个LogIntercepter实例即可 public void setTarget(Object target) { this.target = target; } //横切逻辑方法 public void before(){ System.out.println("before method..."); } public void end(){ System.out.println("end method..."); } //生成代理实例 public Object newProxyInstance(){ return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //横切逻辑+业务逻辑 before(); method.invoke(target, args); end(); return proxy; } }
3. Test
public class Main { public static void main(String[] args) { User user = new User(); user.setId("12"); user.setName("proxy"); //无proxy UserDAOImpl dao = new UserDAOImpl(); dao.save(user); //使用proxy LogIntercepter log = new LogIntercepter(); log.setTarget(dao); UserDAO dao1 = (UserDAO)log.newProxyInstance(); dao1.save(user); } }
4. 测试结果:
user is saved
before method...
user is saved
end method...
5. done!
代理类的大致实现: