代理模式是java中常用的设计模式,代理类通过调用被代理类的相关方法,提供预处理,过滤,事后处理等服务。AOP手动使用代理模式有两个典型的例子,分别为JDK动态代理和CGLIB代理。
项目用到的Junit 项目右键-properties-java build path - library -add library - Junit
一,JDK动态代理
JDK动态代理是通过JDK中的java.lang.reflect.Proxy 类来实现的,下面通过一个案例来说明
1,在eclipse或myeclipse下创建一个web项目导入spring项目所需的jar包
2,在src目录下创建一个包cn.itcast.dao,在改包下创建一个接口UserDao
package cn.itcast.dao;
public interface UserDao {
public void save();
public void update();
public void delete();
public void find();
}
然后在该包下创建接口的实现类UserDaoImpl
package cn.itcast.dao;
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save 添加用户");
}
@Override
public void update() {
System.out.println("update 更新用户");
}
@Override
public void delete() {
System.out.println("delete 删除用户");
}
@Override
public void find() {
System.out.println("find 查找用户");
}
}
3,在src目录下创建包cn.itcast.jdk 在改包下创建切面类MyAspect
package cn.itcast.jdk;
public class MyAspect {
public void myBefore(){
System.out.println("方法执行前");
}
public void myAfter(){
System.out.println("方法执行后");
}
}
4,在cn.itcast.jdk包下创建MyBeanFactory类在该类中通过Proxy实现动态代理
package cn.itcast.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.itcast.dao.UserDao;
import cn.itcast.dao.UserDaoImpl;
public class MyBeanFactory {
public static UserDao getBean(){
final UserDao userDao = new UserDaoImpl();
final MyAspect myAspect = new MyAspect();
return (UserDao)Proxy.newProxyInstance(
MyBeanFactory.class.getClassLoader(),
new Class[]{UserDao.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强前
myAspect.myBefore();
//目标类的方式
Object obj = method.invoke(userDao, args);
//增强后
myAspect.myAfter();
return obj;
}
});
}
}
5,在cn.itcast.jdk包下创建测试类TestJDK
package cn.itcast.jdk;
import org.junit.Test;
import cn.itcast.dao.UserDao;
public class TestJDK {
@Test
public void demo(){
//从工厂获取bean
UserDao userDao = MyBeanFactory.getBean();
userDao.save();
userDao.update();
userDao.delete();
userDao.find();
}
}
运行测试方法demo:
JDK动态代理已经实现
二,CGLIB代理
JDK动态代理用起来非常简单,但是它是有局限性的,使用JDK动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,那么可以使用CGLIB代理
CGLIB是一个高性能开源的代码生成包,他的底层通过使用一个小而快的字节码处理框架ASM来转换字节码,
为一个类创建子类,然后对子类进行增强,解决了无接口代理。所以CGLIB要依赖ASM的包,但是spring核心包
已经为我们集成CGLIB所需的包,所以我们不需在导入ASM的包,下面通过案例来说明
1,在上面项目的cn.itcast.dao包下创建类BookDao
package cn.itcast.dao;
public class BookDao {
public void save() {
System.out.println("save 添加图书");
}
public void update() {
System.out.println("update 更新图书");
}
public void delete() {
System.out.println("delete 删除图书");
}
public void find() {
System.out.println("find 查找图书");
}
}
2,在src目录下创建包cn.itcast.cglib,在该包下创建类MyBeanFactory
package cn.itcast.cglib;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import cn.itcast.dao.BookDao;
import cn.itcast.jdk.MyAspect;
public class MyBeanFactory {
public static BookDao getBean(){
final BookDao bookDao = new BookDao();
final MyAspect myAspect = new MyAspect();
//核心类
Enhancer enhancer = new Enhancer();
//确定需要增强的类
enhancer.setSuperclass(bookDao.getClass());
//添加回调函数
enhancer.setCallback(new MethodInterceptor() {
//interceptor相当于jdk的invoke
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
//之前
myAspect.myBefore();
//目标方法执行
Object obj = arg1.invoke(bookDao, arg2);
//之后
myAspect.myAfter();
return obj;
}
});
//创建代理类
BookDao bookDaoProxy = (BookDao)enhancer.create();
return bookDaoProxy;
}
}
3,在cn.itcast.cjlib包下创建测试类TestCGLIB
package cn.itcast.cglib;
import org.junit.Test;
import cn.itcast.dao.BookDao;
public class TestCGLIB {
@Test
public void demo(){
//从工厂获取bean
BookDao bookDao = MyBeanFactory.getBean();
bookDao.save();
bookDao.update();
bookDao.delete();
bookDao.find();
}
}
运行测试方法:
CGLIB代理已经实现