Spring容器中Aop原理的代理模式
定义:是程序设计中的一种设计模式,我们可以在不改动源码的情况下,在源码的基础上进行功能扩展或者进行一些添加实现(如在目标对象的某方法内进行内容扩展);
而代理模式具体分为三种代理方式
1、静态代理 支持spring可用 mybatis 可用
2、动态代理(JDK代理) 支持spring可用 mybaits可用
3、CGLIB代理 支持 spring可用 hibernate可用 方法或者属性加上final代理会失效
*JDK与CGLIB的实质区别是代理的目标类是否实现了接口
*静态代理和动态代理的共同点是目标对象都实现了接口,也就是说静态代理和JSK代理共同的缺点就是:目标对象和代理对象都需要实现一个或者多个接口 不要接口可使用Cglib代理
静态代理:
先创建一个接口,目标对象和代理对象同时继承该接口
public interface UserBiz{
public boolean login(String user,String pwd);
}
public class UserBizImpl implements UserBiz {
public boolean login(String yc,String str)
{
if("yc".equals(yc)&&"123".equals(str))
{
System.out.println("登陆成功");
return true;
}else
{
System.out.println("登录失败");
return false;
}
}
}
目标对象需要重写方法,代理对象的构造方法里引用目标对象的实例,同时在重写(已经扩展)的方法里必须包含目标对象的方法 ,如此便实现的不改变源码的功能扩展
静态代理spring测试写法:
public class ProxyTest {
@Test
public void testManager()
{
UserBiz ubiz=new UserBizImpl();
Manager manager=new Manager(ubiz);
manager.login("yc", "123");
}
class Manager implements UserBiz{
//目标对象
private UserBiz target;
//构造器中接收目标对象
public Manager(UserBiz target) {
this.target = target;
}
@Override
public boolean login(String user, String pwd) {
boolean flag=target.login(user, pwd);
if(flag)
{
System.out.println("登陆成功2");
}else{
System.out.println("登陆失败2");
}
return (Boolean) null;
}
}
动态代理(也叫JDK代理)
动态代理引用的接口类和对象类同上方的UserBiz,UserBizImpl一致,需要使用java封装的newProxyInstance方法
JDK代理在spring测试类的写法:
public class ProxyTest {
@Test
public void testJDKProxy()
{
//创建被代理对象 用子类创建父类接口对象
UserBiz ubiz=new UserBizImpl();
//创建代理对象 以被代理对象为参数
Proxyer proxyer=new Proxyer();
UserBiz proxyerUbiz= (UserBiz) proxyer.getProxy(ubiz);
//执行代理方法
proxyerUbiz.login("yc","123");
//注:代理对象和被代理对象(目标对象)都是由接口对象来承接
}
}
//此类用来创建代理对象 此Proxyer类差不多都是固定写法
class Proxyer implements InvocationHandler
{
//目标对象,即被代理对象
private Object target;
//以目标对象为参数去创建代理对象
public Object getProxy(Object target)
{
this.target=target;
//Proxy 是JDK提供的代理对象构造器 调用构造器方法
//target.getClass().getClassLoader()是被代理对象的类加载器
//target.getClass().getInterfaces()是被代理对象的接口数组
//this 指的是该接口(InvocationHandler)对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
@Override
//只要被代理的对象方法执行时就会执行此方法
//代理对象 Object proxy
//代理对象执行的方法Method method
//代理对象方法带的参数 Object[] args
//此方法是JDK固定写法 只要目标对象方法执行 此方法也会自动执行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("方法:"+method);
Object ret=method.invoke(target,args);
return ret;
}
}
Cglib代理:
a、需要引入Cglib的jar文件 spring的核心包中已经包括了Cglib的功能可以直接引用
b、目标类不能为final
c、目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法
而代理模式在spring的AOP编程中:如果加入的容器的目标对象有实现接口,选用JDK代理,如果目标对象没有实现接口,用Cglic代理
无接口的对象类;
public class ReplyBiz {
public void reply(String user,String content)
{
System.out.println(user+"回复帖子"+content);
}
}
CGLIB代理测试写法:
//此ProxyTest类差不多都是固定写法,参数可改动
public class ProxyTest {
@Test
public void testCGLIBProxy()
{
//Enhancer允许为非接口类型创建一个Java代理。Enhancer动态创建了给定类型的子类但是拦截了所有的方法。
Enhancer enhancer=new Enhancer();
//以目标对象为参数指定父类
enhancer.setSuperclass(ReplyBiz.class);
//设置方法回调
enhancer.setCallback(new org.springframework.cglib.proxy.MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("方法:"+method);
//调用被代理方法
Object ret=proxy.invokeSuper(obj, args);
return ret;
}
});
//cglib通过enhancer来创建目标对象方法,再调用方法的固定写法
ReplyBiz rbiz=(ReplyBiz) enhancer.create();
rbiz.reply("yc","test");
//注;三种代理方法共同方法一定要在代理过程中调用一次原目标对象的原方法
}
}