动态代理常用的有两种方式
- 基于接口的动态代理
提供者:JDK官方的Proxy类
要求:被代理类最少实现一个接口 - 基于子类的动态代理
提供者:第三方的CGLib
要求:被代理类不能用final修饰的类(最终类)。
如何获取代理对象?(对本来的类的方法进行增强 也就是拦截)
1、首先定义一个功能接口
2、定义一个类,这个类至少实现了一个接口
3、适用JDK官方的Proxy类来创建 刚才我们创建的类 的代理对象
创建的方式:
Proxy.newProxyInstance(三个参数)
参数的含义:
1、ClassLoader: 和被代理对象使用相同的类加载器 类加载器时通过类对象.getClassLoader()方法获得。
2、Interfaces: 和被代理对象具有相同的行为,实现相同的接口
自己创建的类实现的接口时通过类对象.getInterfaces()方法获得。
3、InvocationHandler:如何代理。
执行被代理对象的任何方法,都会经过该方法。
参数:
1、Proxy:代理对象的引用。不一定每次都用得到
2、method:当前执行的方法对象
3、args:执行方法所需的参数。
返回值:
当前执行方法的返回值
1、基于基于接口的动态代理
功能接口
public interface IActor {
/**
* 基本演出
* @param money
*/
public void basicAct(float money);
/**
* 危险演出
* @param money
*/
public void dangerAct(float money);
}
实现接口的类
public class Actor implements IActor{
public void basicAct(float money){
System.out.println("拿到钱,开始基本的表演:"+money);
}
public void dangerAct(float money){
System.out.println("拿到钱,开始危险的表演:"+money);
}
}
基于接口创建代理对象
IActor proxyActor = (IActor) Proxy.newProxyInstance(
actor.getClass().getClassLoader(),
actor.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
Float money = (Float) args[0];
Object rtValue = null;
//每个经纪公司对不同演出收费不一样,此处开始判断
if("basicAct".equals(name)){
if(money > 2000){
rtValue = method.invoke(actor, money/2);
}
}
if("dangerAct".equals(name)){
if(money > 5000){
rtValue = method.invoke(actor, money/2);
}
}
return rtValue;
}
}
});
proxyActor.basicAct(8000f);
proxyActor.dangerAct(50000f);
}
)
2、使用CGLib的Enhancer类创建代理对象
刚才的Actor一个类不实现接口
public class Actor{//没有实现任何接口
public void basicAct(float money){
System.out.println("拿到钱,开始基本的表演:"+money);
}
public void dangerAct(float money){
System.out.println("拿到钱,开始危险的表演:"+money);
}
}
基于子类的动态代理
要求:被代理对象不能时最终类
用到的类为 Enhancer
用到的方法:create(Class,Callback)
方法的参数:
1、Class:被代理对象的字节码
2、Callback:如何代理
Callback时当前执行方法
Actor cglibActor = (Actor) Enhancer.create(actor.getClass(),
new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args,MethodProxy methodProxy) throws Throwable {
String name = method.getName();
Float money = (Float) args[0];
Object rtValue = null;
if("basicAct".equals(name)){
if(money > 2000){
rtValue = method.invoke(actor, money/2);
}
}
if("dangerAct".equals(name)){
if(money > 5000){
rtValue = method.invoke(actor, money/2);
}
}
return rtValue;
}
});
cglibActor.basicAct(10000);
cglibActor.dangerAct(100000);
代理模式的用处举例
我们业务层实现类实现业务层接口 ,调用业务层的方法时,总是要开启事务,确保事务能够完整的执行
但是每一个业务层的方法加上事务的代码是很繁琐的,于是我们可以对业务层实现类进行方法的增强(本质就是对方法进行拦截处理)
public class BeanFactory {
public static IAccountService getAccountService() {
final IAccountService accountService = new AccountServiceImpl();
IAccountService proxyAccountService = (IAccountService) Proxy.newProxyInstance(
accountService.getClass().getClassLoader(),
accountService.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {
Object rtValue = null;
try {
//开启事务
TransactionManager.beginTransaction();
//执行业务层方法
rtValue = method.invoke(accountService, args);
//提交事务
TransactionManager.commit();
}catch(Exception e) {
//回滚事务
TransactionManager.rollback();
e.printStackTrace();
}finally {
//释放资源
TransactionManager.release();
}
return rtValue;
}
});
return proxyAccountService;
}
}
当我们改造完成之后,业务层用于控制事务的重复代码就都可以删掉了。