动态代理
假如有一个Dog类,该类有eat()和sleep()方法;由该类创建了一个dog对象,现在有一个需求,想知道sleep执行了多长时间,该如何实现这个需求呢?
可以使用动态代理来实现这个需求。
关于动态代理的两个重要的类:
1.Proxy:构造动态代理对象的方法Proxy:构造动态代理对象的方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
2.InvocationHandler:只有一个invoke方法:
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。
args - 包含传入代理实例上方法调用的参数值的对象数组.
为了实现计算dog的sleep时间,需要抽象出一个Animal接口,代码为:
Animal.java
代码为:
Dog类实现Animal接口:
Dog.java
代码为:
封装了自己需求的Advice接口:
Advice.java:
MyAdvice.java:
抽象一个返回某个实例target的代理对象的方法:
================================
假如有一个Dog类,该类有eat()和sleep()方法;由该类创建了一个dog对象,现在有一个需求,想知道sleep执行了多长时间,该如何实现这个需求呢?
可以使用动态代理来实现这个需求。
关于动态代理的两个重要的类:
1.Proxy:构造动态代理对象的方法Proxy:构造动态代理对象的方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
loader - 定义代理类的类加载器
interfaces - 代理类要实现的接口列表
h - 指派方法调用的调用处理程序
2.InvocationHandler:只有一个invoke方法:
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。
args - 包含传入代理实例上方法调用的参数值的对象数组.
为了实现计算dog的sleep时间,需要抽象出一个Animal接口,代码为:
Animal.java
代码为:
public
interface Animal {
public
void eat();
public
void sleep();
}
|
Dog.java
代码为:
public
class Dog implements Animal {
public
void eat() {
System.
out.println("狗狗正在吃东西。。" );
}
public
void sleep() {
System.
out.println("狗狗正在睡觉觉。。" );
try {
Thread. sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
|
Advice.java:
public
interface Advice {
void
beforeMethod(Method method);
void
afterMethod(Method method);
}
|
MyAdvice.java:
public
class MyAdvice implements Advice {
long
beginTime=0;
long
endTime=0;
public
void afterMethod(Method method) {
endTime=System. currentTimeMillis();
System.
out.println(method.getName()+"方法执行后。。共睡了:" +(endTime -beginTime )/1000+"秒" );
}
public
void beforeMethod(Method method) {
beginTime=System.currentTimeMillis();
System.
out.println(method.getName()+"方法执行前。。。" );
}
}
|
抽象一个返回某个实例target的代理对象的方法:
public
class ProxyDemo {
/**
* 获取某个target对象的代理对象,并加入自己想要操作的代码,我们称之为advice;
*
*
@param target
* 要去代理的对象;
*
@param advice
* 封装了自己需求的对象;
*
@return target的代理对象;
*/
public
static Object getProxy(final Object target, final Advice advice) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new
InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args)
throws Throwable {
if (method.getName().equals("sleep" )) {// 如果调用的方法是sleep方法;
advice.beforeMethod(method);
// 调用真正的方法前,执行一些操作
Object retValue = method.invoke(target, args);
advice.afterMethod(method);
// 调用方法后,执行一些操作。
return retValue;
}
else {// 调用的是其他方法
Object retValue = method.invoke(target, args);
return retValue;
}
}
});
}
public
static void main(String[] args) {
Animal dog =
new Dog();
Advice advice =
new MyAdvice();
Animal proxyDog = (Animal) getProxy(dog, advice);
proxyDog.eat();
proxyDog.sleep();
/*
* 每次调用proxyDog对象的方法,都会去执行invoke方法,因此可以在invoke方法里对方法的执行实现控制,
* 如如果调用的是sleep方法,那么就加入自己的一些想法,是其他方法则放行,相当于起到了过滤器的左右,这比过滤器实现了更细微程度的控制。
*/
}
}
|
例子二.动态代理更为简单的实现:
//动态代理,针对的是一个已经存在的对象,需要对这个对象的特定的一些方法做改造;例如,改造狗叫的方法;
final Dog dog = new Dog();//Dog有吃和叫这两个方法;
Animal proxy = (Animal) Proxy.newProxyInstance(dog.getClass().getClassLoader(), dog.getClass().getInterfaces()
,
new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("叫" .equals(method.getName())){
System.
out.println("代理狗哈哈哈哈的叫。。。。。" );
return null ;
}
else{
return method.invoke(dog, args);
}
}
});
proxy.吃();
proxy.叫();
|
====================================
动态代理例子三:
使用hibernate进行操作数据库,保存数据时,需要开启事务,现将开启事务的操作交由动态代理对象来做。
创建一个对象的代理对象,需要三个参数:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
自己写一个handler,在handler的invoke方法中,实现开启事务和提交事务。
Class<?>[] interfaces,
InvocationHandler h)
自己写一个handler,在handler的invoke方法中,实现开启事务和提交事务。
Classes为要保存到数据库的实体类。
完整代码:
public
class HibernateUtils {
public
static SessionFactory sessionFactory;
static
{
Configuration configuration =
new Configuration();
configuration.configure();
sessionFactory = configuration.buildSessionFactory();
}
}
============================================
public
class MyTransaction extends HibernateUtils{
private
Transaction transaction;
public
void beginTransaction(){
this.transaction = sessionFactory.getCurrentSession().beginTransaction();
}
public
void commit(){
this.transaction .commit ();
}
}
============================================
public
interface ClassesDao {
public
void saveClasses(Classes classes);
public
void updateClasses(Classes classes);
public
List<Classes> getClasses();
}
============================================
public
class ClassesDaoImpl extends HibernateUtils implements ClassesDao{
@Override
public
void saveClasses(Classes classes) {
sessionFactory.getCurrentSession().save(classes);
}
@Override
public
List<Classes> getClasses() {
return sessionFactory .getCurrentSession().createQuery("from Classes").list();
}
@Override
public
void updateClasses(Classes classes) {
sessionFactory.getCurrentSession().update(classes);
}
}
============================================
/**
* 自己定义一个handler来完成事务操作。
* 1、引入目标类
* 2、引入事务
* 3、完成invoke方法
*/
public
class ClassesDaoInterceptor implements InvocationHandler{
private
ClassesDao target;
private
MyTransaction myTransaction;
public
ClassesDaoInterceptor(ClassesDao target,MyTransaction myTransaction){
this.target = target;
this.myTransaction = myTransaction;
}
@Override
public
Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
/**
* 1、开启事务
* 2、调用目标类的方法
* 3、提交事务
*/
if(method.getName().equals("saveClasses" )||
method.getName().equals(
"updateClasses")){
//开启事务,调用方法,提交事务
this.myTransaction .beginTransaction();//通知
method.invoke(
this.target , args);//目标方法
this.myTransaction .commit();
}
else{
method.invoke(
this.target , args);
}
return null ;
}
}
============================================
/**
* 注意的点
* 1、代理对象的方法体的内容就是拦截器 中invoke方法体的内容
* 2、在客户端,用代理对象调用方法的时候进去了invoke方法
*/
public
class ClassesDaoTest {
@Test
public
void testSaveClasses(){
//目标类
ClassesDao target =
new ClassesDaoImpl();
MyTransaction myTransaction =
new MyTransaction();
ClassesDaoInterceptor interceptor =
new ClassesDaoInterceptor(target, myTransaction);
/**
* 获取动态代理对象
* 1、目标类的类加载器
* 2、目标类实现的所有的接口
* 3、拦截器
*/
ClassesDao targetProxy = (ClassesDao) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
interceptor);
Classes classes =
new Classes();
classes.setCname(
"多对多");
targetProxy.saveClasses(classes);
}
}
============================================
|