JDK动态代理
一个接口
package _6JDK动态代理;
public interface PersonDao {
public Object update();
public void delete();
public void insert();
} 接口实现类
package _6JDK动态代理;
public class PersonDaoImpl implements PersonDao {
@Override
public void delete() {
// TODO Auto-generated method stub
System.out.println("delete");
}
@Override
public void insert() {
// TODO Auto-generated method stub
System.out.println("insert");
}
@Override
public Object update() {
// TODO Auto-generated method stub
System.out.println("update");
return "update_success";
}
} 在代理中用来装配的模块
package _6JDK动态代理;
public class Transaction {
public void beginTransaction(){
System.out.println("开启事务");
}
public void commit(){
System.out.println("结束事务");
}
} 在拦截器中装配模块
package _6JDK动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 拦截器
* @author Think
* 1、引入目标类
* 2、引入事务
* 3、通过构造函数给目标类和事务赋值
* 4、填充invoke方法
*
*/
//需要实现InvocationHandler,所以才说是jdk动态代理
public class PersonInterceptor implements InvocationHandler{
private Object target;//目标类
private Transaction transsaction;//引入事务
public PersonInterceptor(Object target,Transaction transaction){
this.target = target;
this.transsaction = transaction;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//在这里把想要组合在一起的内容组合起来
//只需要组合这一次,以后就不用管了,不像静态代理,每次都要重新写
//感觉静态代码更像是装饰设计模式
// TODO Auto-generated method stub
this.transsaction.beginTransaction();
//返回的是调用的方法的返回值
Object message = method.invoke(this.target, args);//调用目标类的方法
this.transsaction.commit();
return message;
}
} 开始使用代理
package _6JDK动态代理;
import java.lang.reflect.Proxy;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object target = new PersonDaoImpl();
Transaction transaction = new Transaction();
PersonInterceptor interceptor
= new PersonInterceptor(target, transaction);
/**
* 1、目标类的类加载器
* 2、目标类实现的所有的接口
* 3、拦截器
*/
PersonDao persondao = (PersonDao) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
interceptor);
System.out.println(persondao.update());
}
}
JDK的动态代理必须具备四个条件:
目标接口
目标类
拦截器
代理类
总结:
1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。
2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。
3、利用JDKProxy方式必须有接口的存在。
4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。
JDK动态代理优化,类似于struts2的拦截器模式。
拦截器接口,用来装配的
package _7JDK动态代理优化;
public interface Interceptor {
public void interceptor();
} 接口实现,全部是拦截器角色,用来装配的
package _7JDK动态代理优化;
public class Logger implements Interceptor{
@Override
public void interceptor() {
// TODO Auto-generated method stub
System.out.println("logging");
}
}
package _7JDK动态代理优化;
public class Privilege implements Interceptor{
@Override
public void interceptor() {
// TODO Auto-generated method stub
System.out.println("privilege");
}
}
package _7JDK动态代理优化;
public class Security implements Interceptor{
@Override
public void interceptor() {
// TODO Auto-generated method stub
System.out.println("security");
}
}
目标类接口,也就是被代理的类
package _7JDK动态代理优化;
public interface SalaryManager {
public void showSalary();
}
目标类接口的实现
package _7JDK??????????;
public class SalaryManagerImpl implements
SalaryManager {
public void showSalary() {
System.out.println("查看工资");
}
} 目标类和装配模板装配在一起,模板有多个,类似于struts2的拦截器模式
package _7JDK??????????;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
public class SalaryInterceptor implements InvocationHandler{
private Object target;
//把所有切面都放在集合里面 这样????改变的也是结合,下面的invoke的切面整合不用因为增加一个??修改
private List<Interceptor> interceptors;
public SalaryInterceptor(Object target,List<Interceptor> interceptors){
this.target = target;
this.interceptors = interceptors;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
for(Interceptor interceptor:interceptors){
interceptor.interceptor();
}
method.invoke(this.target, args);
return null;
}
} 代理测试类:多个拦截器放在集合里面
package _7JDK动态代理优化;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class SalaryTest {
@Test
public void test(){
Object target = new SalaryManagerImpl();
Logger logger = new Logger();
Security security = new Security();
Privilege privilege = new Privilege();
List<Interceptor> interceptors = new ArrayList<Interceptor>();
interceptors.add(logger);
interceptors.add(security);
interceptors.add(privilege);
SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors);
SalaryManager salaryManager = (SalaryManager)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor);
salaryManager.showSalary();
}
}
cglib产生的代理类是目标类的子类,其他和jdk动态代理一样
1、 CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
2、 用CGlib生成代理类是目标类的子类。
3、 用CGlib生成 代理类不需要接口
4、 用CGLib生成的代理类重写了父类的各个方法。
5、 拦截器中的intercept方法内容正好就是代理类中的方法体
拦截器接口
package _8cglib动态代理;
public interface Interceptor {
public void interceptor();
} 实现类
package _8cglib动态代理;
public class Logger implements Interceptor{
@Override
public void interceptor() {
// TODO Auto-generated method stub
System.out.println("logging");
}
}
package _8cglib动态代理;
public class Privilege implements Interceptor{
@Override
public void interceptor() {
// TODO Auto-generated method stub
System.out.println("privilege");
}
}
package _8cglib动态代理;
public class Security implements Interceptor{
@Override
public void interceptor() {
// TODO Auto-generated method stub
System.out.println("security");
}
} 目标类,和jdk的区别就是这里只有具体类,没有对应的接口
package _8cglib动态代理;
public class SalaryManagerImpl {
public void showSalary() {
System.out.println("工资");
}
} 装配类,装配方式和jdk动态代理有点区别
package _8cglib???????;
import java.lang.reflect.Method;
import java.util.List;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class SalaryInterceptor implements MethodInterceptor{
private Object target;
private List<Interceptor> interceptors;
public SalaryInterceptor(Object target,List<Interceptor> interceptors){
this.target = target;
this.interceptors = interceptors;
}
//固定写法
public Object createProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setCallback(this);
enhancer.setSuperclass(this.target.getClass());
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
for(Interceptor interceptor:interceptors){
interceptor.interceptor();
}
arg1.invoke(this.target, arg2);
return null;
}
} 代理测试类
package _8cglib动态代理;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class SalaryTest {
@Test
public void test(){
Object target = new SalaryManagerImpl();
Logger logger = new Logger();
Security security = new Security();
Privilege privilege = new Privilege();
List<Interceptor> interceptors = new ArrayList<Interceptor>();
interceptors.add(logger);
interceptors.add(security);
interceptors.add(privilege);
SalaryInterceptor interceptor = new SalaryInterceptor(target, interceptors);
SalaryManagerImpl proxy = (SalaryManagerImpl)interceptor.createProxy();
proxy.showSalary();
}
}
spring有两种代理方式:
1. 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口
2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。
总结:不管采用JDK动态代理生成代理类还是采用CGLIB生成动态代理类。目标类中的所有方法都被拦截下来。而在哪个方法里做比如权限的判断、安全性的检查等一系列工做必须在拦截器中作相应的判断。但是这样的编程形式给程序的编写带来了一定的麻烦。
1、 在拦截器中控制哪些方法将被做权限判断、安全性检查等是一件比较困难的事情。
A. 采取这样的配置目标类只能是一个,所以如果用这种方法做权限控制,得写很多代理,这样给代码的书写造成了困难。
B. 每一个类中的每一个方法如果都有不同的权限(实际的系统往往都是这样的),在拦截器中的判断代码书写会很困难。
2、 这样的代码也会导致硬编码,也就是说我们必须在拦截器中写一些权限判断等事情,会导致拦截器中代码量的增大,造成维护的麻烦。
原文:http://my.oschina.net/u/2356176/blog/469093