一、代理模式实现aop
public interface IHello {
void sayHello(String name);
}
public class Hello implements IHello {
@Override
public void sayHello(String name) {
System.out.println(name+" say hello");
}
}
代理类
public class HelloProxy implements IHello {
private IHello hello;
public HelloProxy(IHello hello){
this.hello=hello;
}
@Override
public void sayHello(String name) {
System.out.println("before....");
hello.sayHello(name);
System.out.println("after....");
}
}
客户端
public class Test {
public static void main(String[] args){
IHello hello=new HelloProxy(new Hello());
hello.sayHello("persia");
}
}
二、JDK的动态代理反射实现aop
JDK动态代理只能代理接口
/**
* 使用JDK提供的动态代理
* @author scipio
* @created 2013-10-21
*/
public class DynaProxyHello implements InvocationHandler{
private Object target;
//动态生成代理对象
public Object bind(Object target){
this.target=target;
return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),this.target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before..... ");
Object result=method.invoke(target,args);
System.out.println("after.....");
return result;
}
}
客户端
public class Test {
public static void main(String[] args){
/**
* 只能代理接口
*/
IHello hello= (IHello) new DynaProxyHello().bind(new Hello());
// Hello hello = (Hello) new DynaProxyHello().bind(new Hello());
hello.sayHello("persia");
}
}
三、Aspect方式(JDK实现)
1、定义拦截后要执行的方法
/**
* 拦截指定方法后要执行的方法
* @author scipio
* @created 2013-10-21
*/
public class CrossCutting {
public void before(){
System.out.println("before...");
}
public void after(){
System.out.println("after...");
}
}
2、模拟Aop
/**
* 使用java的反射
* 进行aop功能的模拟
* @author scipio
* @created 2013-10-21
*/
public class Aop {
private static CrossCutting cut=new CrossCutting();
private static ReflectUtils rfBefore=new ReflectUtils(cut,"before");
private static ReflectUtils rfAfter=new ReflectUtils(cut,"after");
public static void beforeAdvice(Object target,String methodName,Object ... params){
Class cls=target.getClass();
Method[] methods=cls.getDeclaredMethods();
for(int i=0;i<methods.length;i++){
if(methods[i].getName().equals(methodName)){
rfBefore.invokeMethod();
new ReflectUtils(target,methodName,params).invokeMethod();
}
}
}
public static void afterAdvice(Object target,String methodName,Object... params){
Class cls=target.getClass();
Method[] methods=cls.getDeclaredMethods();
for(int i=0;i<methods.length;i++){
if(methods[i].getName().equals(methodName)){
new ReflectUtils(target,methodName,params).invokeMethod();
rfAfter.invokeMethod();
}
}
}
public static void aroundAdvice(Object target,String methodName,Object... params){
Class cls=target.getClass();
Method[] methods=cls.getDeclaredMethods();
for(int i=0;i<methods.length;i++){
if(methods[i].getName().equals(methodName)){
rfBefore.invokeMethod();
new ReflectUtils(target,methodName,params).invokeMethod();
rfAfter.invokeMethod();
}
}
}
}
3、拦截对象
/**
* 要被拦截的方法
* @author scipio
* @created 2013-10-21
*/
public interface Crud {
public void add(String user);
public void modify(String user);
public void delete(String user);
}
/**
* 要被拦截的方法
* @author scipio
* @created 2013-10-21
*/
public class CrudImpl implements Crud {
@Override
public void add(String user) {
System.out.println("new user:");
}
@Override
public void modify(String user) {
System.out.println("modify user");
}
@Override
public void delete(String user) {
System.out.println("delete user");
}
}
4、客户端及工具类
public class Test {
public static void main(String[] args){
Crud crud=new CrudImpl();
Aop.beforeAdvice(crud,"modify","persia");
}
}
/**
* java反射的一些帮助方法
* 通过传入的类,拦截要执行的方法名
* 返回后直接invoke即可
* 具体见aop
* 无其他意义,不是经典模式,可以去掉
* @author scipio
* @created 2013-10-21
*/
public class ReflectUtils {
private Class targetClass;
private Object target;
private Method targetMethod;
private Object[] params;
public ReflectUtils(Object target,String methodName,Object ... params){
this.target=target;
this.targetClass=target.getClass();
this.params=params;
Class[] cls=new Class[params.length];
for(int i=0;i<params.length;i++){
cls[i]=params[i].getClass();
}
try {
this.targetMethod=targetClass.getMethod(methodName,cls);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public void invokeMethod(){
try {
this.targetMethod.invoke(target,params);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
四、Aspect方式(Cglib实现)
1、拦截后要执行的方法
/**
* 通过cglib进行拦截
* @author scipio
* @created 2013-10-21
*/
public class AroundCutting implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before...."+method);
//直接invoke会造成stack over flow
// Object result = proxy.invoke(o, args);
Object result = proxy.invokeSuper(o, args);
System.out.println("after..."+method);
return result;
}
}
2、Cglib模拟aop
/**
* cglib实现aop
* @author scipio
* @created 2013-10-21
*/
public class CglibAOP {
private Enhancer enhancer = new Enhancer();
/**
* 使用Cglib进行动态代理,是创建一个子类继承至目标类,所以不需要像GDK动态代理那样提供一个接口,这样节约了类的个数。
* JDK动态代理的特点:不能代理类,只能代理接口
* CGLIB动态代理的特点:能代理类和接口,不能代理final类
* 动态代理的本质:用来实现对目标对象进行增强,最终表现为类,只不过是动态创建子类,不用手工生成子类。
* @param clz
* @return
*/
private MethodInterceptor interceptor;
public CglibAOP(MethodInterceptor interceptor){
this.interceptor=interceptor;
}
public Object getProxy(Class clz){
//生成指定类对象的子类,也就是重写类中的业务函数
enhancer.setSuperclass(clz);
//这里是回调函数,加入intercept()函数
enhancer.setCallback(interceptor);
//创建这个子类对象
return enhancer.create();
}
}
3、被拦截对象
/**
* 要被拦截的方法
* @author caibosi
* @created 2013-10-21
*/
public class CrudImpl {
public void add(String user) {
System.out.println("new user:");
}
//用static方法的话,则拦截不了
public void modify(String user) {
System.out.println("modify user"+user);
}
public void delete(String user) {
System.out.println("delete user");
}
}
4、客户端
public class Test {
public static void main(String[] args){
CglibAOP aop=new CglibAOP(new AroundCutting());
CrudImpl crud= (CrudImpl) aop.getProxy(CrudImpl.class);
crud.modify("modify name");
}
}
5、高级回调功能
/**
* cglib callback filter
* 根据不同方法进行不同的拦截
* @author scipio
* @created 2013-10-24
*/
public class CglibCallbacks {
public static void main(String[] args){
//声明cglib增强类
Enhancer enhancer = new Enhancer();
//设置被代理类
enhancer.setSuperclass(CrudImpl.class);
//set callbacks
Callback[] callbacks = new Callback[]{
NoOp.INSTANCE,new AddCallback(),new ModifyCallback(),new DeleteCallback()
};
//设定拦截方法
enhancer.setCallbacks(callbacks);
//设定方法对应的拦截
enhancer.setCallbackFilter(new DaoFilter());
//通过增强类获取代理类
CrudImpl proxyCrud = (CrudImpl)enhancer.create();
proxyCrud.modify("persia");
proxyCrud.add("linda");
proxyCrud.delete("susan");
}
}
class AddCallback implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before....cutting add method");
Object result = proxy.invokeSuper(o, args);
System.out.println("after...cutting add method");
return result;
}
}
class ModifyCallback implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before....cutting modify method");
Object result = proxy.invokeSuper(o, args);
System.out.println("after...cutting modify method");
return result;
}
}
class DeleteCallback implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before....cutting delete method");
Object result = proxy.invokeSuper(o, args);
System.out.println("after...cutting delete method");
return result;
}
}
/**
* 此方法用来决定哪个方法
* 被那个callback拦截
* 返回index,对应callbacks数组
*/
class DaoFilter implements CallbackFilter{
@Override
public int accept(Method method) {
String methodName = method.getName();
System.out.println("method:"+methodName);
if(methodName.equals("delete")){
return 3;
}else if(methodName.equals("add")){
return 1;
}else if (methodName.equals("modify")){
return 2;
}
//0对应了NoOp.INSTANCE的callback,表示不做任何事情
return 0;
}
}
五、要点
1、JDK只能基于接口动态代理
2、Cglib基于接口和非final类代理,不能代理static方法