特点:代理类实现和被代理类相同的接口,并使用构造方法传递被代理类对象的引用,重新接口中的方法
需要共同的接口:
public interface IUserService {
//登录
public void login(String username,String password);
//注册
public void regist();
}
具体的实现类:
public class UserServiceImpl implements IUserService {
@Override
public void login(String username, String password) {
System.out.println("登录功能.......");
}
@Override
public void regist() {
System.out.println("注册功能.......");
}
}
代理类:
public class Proxy implements IUserService {
//得到目标对象
private IUserService target;
//使用构造方法传递目标对象
public Proxy(IUserService target) {
super();
this.target = target;
}
@Override
public void login(String username, String password) {
System.out.println("增强方法前");
target.login(username, password);
System.out.println("增强方法后");
}
@Override
public void regist() {
System.out.println("增强方法前");
target.regist();
System.out.println("增强方法后");
}
public static void main(String[] args) {
//创建具体的实现类对象
IUserService userService = new UserServiceImpl();
//创建代理对象,并通过构造传递具体对象
Proxy proxy = new Proxy(userService);
//执行代理对象的方法
proxy.login("tony", "123456");
}
}
执行结果:
增强方法前
登录功能.......
增强方法后
总结:
从上面的代码中可以看出静态代理类,将代码写死了,如果需要这个代理类代理多个类那么就需要为每个类编写代码,这样做不利于程序的扩展,现实中一般不会这么做的
下面使用JDK原生的动态代理的方式实现代码的增强:
public class JDKProxyFactory implements InvocationHandler {
private Object target;
public JDKProxyFactory(Object target) {
super();
this.target = target;
}
// 创建代理对象
public Object createProxy() {
// 1.得到目标对象的类加载器
ClassLoader classLoader = target.getClass().getClassLoader();
// 2.得到目标对象的实现接口
Class>[] interfaces = target.getClass().getInterfaces();
// 3.第三个参数需要一个实现invocationHandler接口的对象
Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaces, this);
return newProxyInstance;
}
@Override
// 第一个参数:代理对象.一般不使用;第二个参数:需要增强的方法;第三个参数:方法中的参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 增强前
System.out.println("这是增强方法前......");
Object invoke = method.invoke(target, args);
// 增强后
System.out.println("这是增强方法后......");
return invoke;
}
public static void main(String[] args) {
// 1.创建对象
UserServiceImpl userService = new UserServiceImpl();
// 2.创建代理对象
JDKProxyFactory proxy = new JDKProxyFactory(userService);
// 3.调用代理对象的增强方法,得到增强后的对象
IUserService createProxy = (IUserService) proxy.createProxy();
createProxy.regist();
}
}
总结:
JDK动态代理类实现了InvocationHandler接口。在重写的invoke方法中可以看出,JDK动态代理的基础是反射(method.invoke(对象,参数))Proxy.newProxyInstance(),这个方法,字面上的意思是新建一个代理类的实例,这一点就和静态代理不同了。里面的参数有三个 类加载器、所有的接口,得到InvocationHandler接口的子类实例。
这就是JDK动态代理,该代理有以下几种特点:
1、Interface:对于JDK Proxy,业务类是需要一个Interface的,这是一个缺陷;
2、Proxy:Proxy类是动态产生的,这个类在调用Proxy.newProxyInstance()方法之后,产生一个Proxy类的实力。实际上,这个Proxy类也是存在的,不仅仅是类的实例,这个Proxy类可以保存在硬盘上;
3、Method:对于业务委托类的每个方法,现在Proxy类里面都不用静态显示出来
4、InvocationHandler:这个类在业务委托类执行时,会先调用invoke方法。invoke方法在执行想要的代理操作,可以实现对业务方法的再包装。
CGLIB(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类.如果你要单独使用CGLIB,那么需要导入cglib的jar包还需要一个asm相关jar包,但是spring框架的spring-core.jar包中已经集成了cglib与asm.
CGLib是针对类来实现代理的,他的原理是对指定的目标生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
注意:jdk的动态代理只可以为接口去完成操作,而cglib它可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理。
public class CglibProxyFactory implements MethodInterceptor {
//得到目标对象
private Object target;
//使用构造方法传递目标对象
public CglibProxyFactory(Object target) {
super();
this.target = target;
}
//创建代理对象
public Object createProxy(){
//1.创建Enhancer
Enhancer enhancer = new Enhancer();
//2.传递目标对象的class
enhancer.setSuperclass(target.getClass());
//3.设置回调操作
enhancer.setCallback(this);
return enhancer.create();
}
@Override
//参数一:代理对象;参数二:需要增强的方法;参数三:需要增强方法的参数;参数四:需要增强的方法的代理
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 增强前
System.out.println("这是增强方法前......");
Object invoke = methodProxy.invoke(target, args);
// 增强后
System.out.println("这是增强方法后......");
return invoke;
}
public static void main(String[] args) {
// 1.创建对象
UserServiceImpl userService = new UserServiceImpl();
// 2.创建代理对象
CglibProxyFactory proxy = new CglibProxyFactory(userService);
// 3.调用代理对象的增强方法,得到增强后的对象
IUserService createProxy = (IUserService) proxy.createProxy();
createProxy.regist();
}
}