java中的代理分为静态代理和动态代理,静态代理一种实现方式,一个代理类只能代理一个对应的类,动态代理有jdk动态代理和CGLib动态代理,其中CGLib动态代理方式是Spring框架中提供的代理方式。
以事务代理为例---->>
静态代理
TXManager.java:
public class TXManager {
public void begin(){
System.out.println("事务开启~~");
}
public void commit(){
System.out.println("事务关闭~~");
}
}
UserService.java
//被代理的类
public interface UserService {
public void saveUser();
}
UserServiceImpl.java
//实现接口
public class UserServiceImpl implements UserService{
@Override
public void saveUser() {
System.out.println("保存了一个用户:");
}
}
下面是静态代理类,静态代理类需要实现被代理的接口,被代理的类是UserServiceImpl,其对应的接口为UserService。
StaticProxy.java
/**
* 静态代理类:需要实现被代理层的接口及其所包含的方法
*/
public class StaticProxy implements UserService {
//需要代理的目标类
private UserServiceImpl target;
//事务对象
private TXManager txManager;
public StaticProxy() {
target = new UserServiceImpl();
txManager = new TXManager();
}
@Override
public void saveUser() {
txManager.begin();
target.saveUser();
txManager.commit();
}
}
在UserServlet中使用代理对象调用UserServiceImpl里面的saveUser()方法:
//UserServlet.java
public class UserServlet {
public void saveUser(){
StaticProxyproxy = new StaticProxy();
proxy.saveUser();
}
}
下面测试类测试UserServlet调用是否成功:
MyTest.java
public class MyTest {
@Test
public voidtestStaticProxy(){
UserServletuserServlet = new UserServlet();
userServlet.saveUser();
}
}
测试结果:
总结:
优点:静态代理将事务代码从service层中提取出来,降低了耦合度,易于扩展;
缺点:一个静态代理类只能代理一个类,一个代理中重复代码太多,不能复用。
动态代理
jdk动态代理
沿用以上代码,仅修改代理类和UserServlet类。
代理类:
jdkDynamicProxy.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.tedu.manager.TXManager;
public class jdkDynamicProxy{
private TXManager txManager;
public jdkDynamicProxy() {
txManager = new TXManager();
}
//target用final修饰是因为通知系统这个参数最后无论如何都会使用,如果不加则会认为使用不了
public Object getProxy(final Object target){
//创建一个代理类的实例对象
//参数介绍:1:类加载器,为了创建功能相同的类
//参数介绍:2:目标类的接口
//参数介绍:3:回调函数,代理对象执行任何方法的时候会回调
Objectproxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy,
Methodmethod, Object[] args)
throws Throwable {
txManager.begin();
Objectresult = method.invoke(target, args);
txManager.commit();
return result;
}
});
return proxy;
}
}
下面修改UserServlet类:
import cn.tedu.proxy.jdkDynamicProxy;
import cn.tedu.service.UserService;
import cn.tedu.service.UserServiceImpl;
/**
* 调用静态代理使用方法
*/
public class UserServlet {
public void saveUser(){
//得到目标类
UserService userService = newUserServiceImpl();
//创建动态代理对象
jdkDynamicProxy dynamicproxy =new jdkDynamicProxy();
//通过动态代理对象获取动态代理类
UserService proxyService = (UserService)dynamicproxy.getProxy(userService);
//执行动态代理类的方法
proxyService.saveUser();
}
}
测试:
总结:
优点:jdk动态代理延续了静态代理的优点,提高了代码重用性,一个代理类可以代理多个Service生成代理对象;
缺点:1.JDK的动态代理必须要求被代理类有接口
2.代理类中的方法是统一添加了事务或者权限控制代码,不容易进行方法的过滤
CGLib动态代理
增强器Enhancer相关的jar包
同样只需修改代理类和UserServlet类即可。
代理类:
CGLibDynamicProxy.java
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
importorg.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import cn.tedu.manager.TXManager;
public classCGLibDynamicProxy {
public static Object getProxy(final Object target,final TXManager txManager){
//创建一个增强器
Enhancerenhancer = new Enhancer();
//给增强器设置接口,接口为目标代理类的接口
enhancer.setInterfaces(target.getClass().getInterfaces());
//设置父类,父类是代理类的父类,如果目标类没有接口,则使用此方式
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Methodmethod, Object[] args,
MethodProxyarg3) throws Throwable {
txManager.begin();
Objectresult = method.invoke(target, args);
txManager.commit();
return result;
}
});
//创建代理对象并返回
return enhancer.create();
}
}
修改UserServlet
UserServlet.java
public class UserServlet {
public void saveUser(){
//得到目标类
UserServiceuserService = new UserServiceImpl();
//通过动态代理对象获取动态代理类
UserServiceImplproxyService = (UserServiceImpl) CGLibDynamicProxy.getProxy(userService,new TXManager());
//执行动态代理类的方法
proxyService.saveUser();
}
}
测试结果:
总结:
优点:1.延续jdk动态代理的优势 2.不一定有接口
缺点:代理类中的方法是统一添加了事务或者权限控制代码,不容易进行方法的过滤,方法过滤可以用Spring框架提供的AOP切面编程方法进行过滤。
ps:初入java,不足之处请大家不吝指正。