实现接口,使用代理对象完成AOP模拟
AOP在项目中主要实现权限的控制,包括细粒度和粗粒度的区分。对那些方法实施拦截,拦截之后干什么,就是属于横切性关注点。
主要通过代理模式来实现
–静态代理
–动态代理:通过JDK或第三方框架生成字节码,如Proxy。目标对性要实现代理的接口。
代码:
- 创建service和bean对象
package cn.gc.service;
public interface PersonService {
public void save(String name);
public void update(String name, String personId);
public String getName(String personId);
}
package cn.gc.service;
public class PersonServiceBean implements PersonService {
//拦截所有业务方法
//判断用户是否有权限 有(user不为null)则允许执行业务方法 无则不执行业务方法
private String user = null;
public String getUser() {
return user;
}
public PersonServiceBean(String user) {
this.user = user;
}
@Override
public String getName(String personId) {
// TODO Auto-generated method stub
return "XXX";
}
@Override
public void save(String name) {
// TODO Auto-generated method stub
System.out.println("save方法");
}
@Override
public void update(String name, String personId) {
// TODO Auto-generated method stub
System.out.println("update方法");
}
}
- 代理模式创建代理对象
package cn.gc.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.gc.service.PersonServiceBean;
/**
* 代理工厂
*
* @author gc
*
*/
public class JDKProxyFactory implements InvocationHandler {
private Object obj;
/**
* 创建代理实例,在调用代理对象的业务方法时,会被this对象所拦截
*
* @param obj
* @return
*/
public Object createproxyInstance(Object obj) {
this.obj = obj;
// 在调用代理对象的业务方法时,会被this对象所拦截,而this对象通过执行invoke方法
return Proxy.newProxyInstance(this.obj.getClass().getClassLoader(),
this.obj.getClass().getInterfaces(), this);
}
/**
* 实现InvocationHandler接口的方法,把方法的调用委派给目标对象
*
* @param proxy
* 代理对象
* @param method
* 拦截到的方法
* @param args
* 传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
PersonServiceBean beanImpl =(PersonServiceBean)this.obj;
Object result = null;
if(beanImpl.getUser()!=null){
//用户名不为空才执行业务方法
result = method.invoke(obj, args);
}
return result;
}
}
- junit测试
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import cn.gc.aop.JDKProxyFactory;
import cn.gc.service.PersonService;
import cn.gc.service.PersonServiceBean;
public class AOPTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test
public void proxyTest() {
JDKProxyFactory jpf = new JDKProxyFactory();
// 代理对象要通过接口的形式来实现,因为代理对象实现了接口。
// jpf.createproxyInstance(new PersonServiceImpl("xxx"));
/* //控制台输出
PersonService service = (PersonService) jpf
.createproxyInstance(new PersonServiceImpl("vv"));
*/
//控制台不输出
PersonService service = (PersonService) jpf
.createproxyInstance(new PersonServiceBean(null));
service.save("save le ");
}
}
- 结果
传入有参数的对象控制台会输出,传入null控制台无输出
使用spring中cglib实现AOP功能
通过spring2.5提供的cglib的jar文件实现代理。
过程和实现JDK的思路一样 只不过工厂类变成如下的方式:
package cn.gc.aop;
import java.lang.reflect.Method;
import cn.gc.service.PersonServiceBean;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CGlibProxyFactory implements MethodInterceptor{
private Object obj;
/**
* 创建代理实例,在调用代理对象的业务方法时,会被this对象所拦截
*
* @param obj
* @return
*/
public Object createproxyInstance(Object obj) {
this.obj = obj;
//必须设置父类(目标类)
Enhancer enhancer = new Enhancer();
//把目标类设置为代理对象的父类,则代理对象会产生目标对象的子类,
//这个子类中会覆盖目标类中所有非final的所有方法。在覆盖的的代码中添加自身的代码
enhancer.setSuperclass(this.obj.getClass());
//设置回调方法,当代理对象的业务方法被调用的时候这个毁掉方法会被执行(就是拦截)
//要想实现这个毁掉必须要实现接口--MethodInterceptor
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 回调方法
* @param proxy
* 代理对象
* @param method
* 拦截到的方法
* @param args
* 传入的参数
* @param MethodProxy 方法的代理对象
*/
@Override
public Object intercept(Object arg0, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
PersonServiceBean beanImpl =(PersonServiceBean)this.obj;
Object result = null;
if(beanImpl.getUser()!=null){
//用户名不为空才执行业务方法
result = methodProxy.invoke(obj, args);
}
return result;
}
}
一些AOP概念
–横切性关注点
AOP在项目中主要实现权限的控制,包括细粒度和粗粒度的区分。对那些方法实施拦截,拦截之后干什么,就是属于横切性关注点。
–什么是切面?
对横切性关注点的抽象的实现的过程,如上面的类就是一个切面。和类比较相似,类是对物体特征的抽象,而切面是对横切性关注点实现的过程。
–连接点
被拦截的方法。spring中连接点是方法,而其他框架中也可能是类或者构造器。
–切入点
对连接点进行拦截的定义
–通知
在拦截到连接点之后的通知,通知分前置通知,后置通知,异常通知,最终通知,环绕通知。
–目标对象
代理的目标对象 如上所例为bean对象。
–织入
将切面应用到目标对象并导致代理对象创建的过程。例如bean无法进行权限判断,但我们对他拦截 创建代理对象在应用到目标对象。
–引入
在不修改原代码的情况下,为这个类在运行期动态在这个类的代理对象创建一些方法。