Proxy(浅解及示例)
AOP(Aspecct Oriented Programming)面向切面编程。
主要的功能:日志记录,性能统计,安全控制,事务处理,异常处理等。
主要的意图:将日志记录,性能统计等业务代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中去,进而改变这些行为佛如时候不影响业务逻辑代码。
Proxy:代理
动态代理主要是在运行时期穿件一个以实现一组特定接口事务代理类,拦截对目标对象方法的调用。也就是说被代理的对象调用这些方法前后去做一些事情例如事务。日志等。(通俗的解释)。
我们可以画一个自己的代理如右:
示例代码如下(包含包名):
1.建立一个PersonService接口:
package cn.itcast.service;
public interface PersonService {
public void save(String name);
public void update(String name,Integer personid);
public String getPersonName(Integer personid);
}
2.创建接口的实现类PersonServiceBean:
package cn.itcast.servicebean;
import cn.itcast.service.PersonService;
public class PersonServiceBean implements PersonService {
private String user;
public String getUser() {
return user;
}
//无参构造函数
public PersonServiceBean() {}
//有参构造函数
public PersonServiceBean(String user) {
this.user = user;
}
public String getPersonName(Integer personid) {
return "xxx";
}
public void save(String name) {
System.out.println("这是一个save方法");
}
public void update(String name, Integer personid) {
System.out.println("这是一个update方法");
}
}
3.创建一个代理工厂类JDKProxyFactory:
package cn.itcast.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.itcast.servicebean.PersonServiceBean;
public class JDKProxyFactory implements InvocationHandler {
private Object targetObject;
public Object createProxyInstance(Object targetObject){
this.targetObject=targetObject;
return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), this.targetObject.getClass().getInterfaces(), this);
}
//接口的实现方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
PersonServiceBean bean=(PersonServiceBean) this.targetObject;
Object result=null;
if(bean.getUser()!=null){ //取得用户名说明有用户权
result=method.invoke(targetObject, args);
}
return result;
}
}
4.建立一个测试junit用例AopTest:
package cn.itcast.test;
import org.junit.BeforeClass;
import org.junit.Test;
import cn.itcast.aop.JDKProxyFactory;
import cn.itcast.service.PersonService;
import cn.itcast.servicebean.PersonServiceBean;
public class AopTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test
public void proxyTest(){
JDKProxyFactory proxy=new JDKProxyFactory();
PersonService service=(PersonService) proxy.createProxyInstance( new PersonServiceBean("xxx"));//返回的类要用到接口对象
service.save("user");
}
}
5测试结果:
当PersonService service=(PersonService) proxy.createProxyInstance( new PersonServiceBean("xxx"));//返回的类要用到接口对象
即当user为“xxx”存在的时候,单元测试条通过,控制台输出:这是一个save方法
当PersonService service=(PersonService) proxy.createProxyInstance( new PersonServiceBean());//返回的类要用到接口对象
即当user不存在的时候,单元测试条通过,控制台无打印输出,即方法没有被调用。
说明:在上述例子中,user作为目标对象调用方法的判断条件,存在则可调用目标对象的方法,没有则无法调用目标对像的方法。
代理对象就像现在明星的代理人(经纪人)代表明星向邀请者进行谈判协商有关事宜,而真正的实施者是明星本人,代理人在条件满足的条件下,能确保明星的被要求的活动外,而进行其他事宜。比如说和邀请者洽谈的出场费用等问题。
</pre><p></p><p>接上文:</p><p>如果业务逻辑层没有实现接口:即PersonServiceBean没有实现PersonService 接口,就不能用实现EnvocationHandler接口来创建一个代理工厂类了。这时候就需要使用CGLIB来创建代理对象的工厂了:首先需要把cglib-nodep-2.1_3.jar 包加入到构建路径里,示例代码如下:</p><p>1.personServiceBean2与personServiceBean代码一样 只是实现任何接口,CGlibProxyFactory类如下:</p><p><pre name="code" class="java">package cn.itcast.aop;
import java.lang.reflect.Method;
import cn.itcast.servicebean.PersonServiceBean2;
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 targetObject;
public Object createProxyInstance(Object targetObject){
this.targetObject=targetObject;
Enhancer enhancer=new Enhancer();
//设置其父类,代理类覆盖目标类中的非final修饰的所有方法,并添加自身的代码
enhancer.setSuperclass(this.targetObject.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object arg0, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {//环绕通知
PersonServiceBean2 bean=(PersonServiceBean2) this.targetObject;
Object result=null;
if(bean.getUser()!=null){//取得用户名说明有用户权
//......advice()-->前置通知
try{
result=method.invoke(targetObject, args);
// afteradvice()-->后置通知
}catch(RuntimeException e) {
//exceptionadvice()-->例外通知
}finally{
//finallyadvice();-->最终通知
}
}
return result;
}
}
2.在测试方法中添加测试方法:
@Test
public void proxyTest2(){
CGlibProxyFactory cglibProcyFactory=new CGlibProxyFactory();
PersonServiceBean2 service=(PersonServiceBean2) cglibProcyFactory.createProxyInstance( new PersonServiceBean2("xxx"));
service.save("user");
}
3.测试结果同前面的测试结果。
说明:在业务逻辑层没有实现接口。就要用到CGLIB来创建代理类的,这种情况下的代理类覆盖目标类中的非final修饰的所有方法,并根据业务的需要添加自身的代码。