一.概念
举个例子:一个公司是卖摄像头的,但公司不直接跟用户打交道,而是通过代理商跟用户打交道。如果:公司接口中有一个卖产品的方法,那么公司需要实现这个方法,而代理商也必须实现这个方法。如果公司卖多少钱,代理商也卖多少钱,那么代理商就赚不了钱。所以代理商在调用公司的卖方法后,加上自己的利润然后再把产品卖给客户。而客户不直接跟公司打交道,或者客户根本不知道公司的存在,然而客户最终却买到了产品。
专业点:代理模式是对象的结构型模式,代理模式给某一个对象提供代理,并由代理对象控制原对象(目标对象,被代理对象)的引用。简单点说,就是通过一个工厂生成一个类的代理对象,当客户端使用的时候不直接使用目标对象,而是直接使用代理对象。
二.jdk的静态代理
jdk的静态代理要求,目标对象和代理对象都需要实现相同的接口。然后提供给客户端使用。这个代理对客户端是可见的,
给出例子:
1.创建接口,
public interface UserService {
public void addUser(String userId,String userName);
public void delUser(String userId);
public void modfiyUser(String userId,String userName);
public String findUser(String userId);
}
2.实现这个接口的目标对象:
public class UserServiceImpl implements UserService {
@Override
public void addUser(String userId, String userName) {
System.out.println("UserServiceImpl addUser userId->>"+userId);
}
@Override
public void delUser(String userId) {
System.out.println("UserServiceImpl delUser userId->>"+userId);
}
@Override
public void modfiyUser(String userId, String userName) {
System.out.println("UserServiceImpl modfiyUser userId->>"+userId);
}
@Override
public String findUser(String userId) {
System.out.println("UserServiceImpl findUser userId->>"+userId);
return "张山";
}
}
3.为目标对象创建代理对象,UserServiceImplProxy.java代理对象持有目标对象的引用。
public class UserServiceImplProxy implements UserService {
private UserService userService;
public UserServiceImplProxy(UserService userService){
this.userService = userService;
}
@Override
public void addUser(String userId, String userName) {
try {
System.out.println("开始执行:addUser");
userService.addUser(userId, userName);
System.out.println("addUser执行成功。");
} catch (Exception e) {
System.out.println("addUser执行失败。");
}
}
@Override
public void delUser(String userId) {
}
@Override
public void modfiyUser(String userId, String userName) {
}
@Override
public String findUser(String userId) {
return null;
}
}
4.最后调用代理对象完成功能
public class Client {
public static void main(String[] args) {
//向上转型
UserService userService = new UserServiceImplProxy(new UserServiceImpl());
userService.addUser("001", "centre");
}
}
三.jdkdong动态代理
静态代理要为每个目标类创建一个代理类,当需要代理的对象太多了,那么代理类也就变得很多,同时代理类违背了可重复代理只写一次的原则。jdk给我们提供了动态代理。其原理图如下:
jdk的动态要求目标对象必须要实现接口,因为它创建代理对象的时候是根据接口创建。如果不实现接口,jdk无法给目标对象创建代理。被代理对象可以实现多个接口,创建代理时指定创建某个接口的代理对象就可以调用该接口定义的方法了。
1.首先定义这两个接口:service接口和userService接口
public interface Service {
public void sayHello(String name);
public int addOperter(int num,int num2);
}
public interface UserService {
public void addUser(String userId,String userName);
public void delUser(String userId);
public void modfiyUser(String userId,String userName);
public String findUser(String userId);
}
2.定义实现这两个接口的目标对象
public class UserServiceImpl implements UserService ,Service{
@Override
public void addUser(String userId, String userName) {
System.out.println("UserServiceImpl addUser userId->>"+userId);
}
@Override
public void delUser(String userId) {
System.out.println("UserServiceImpl delUser userId->>"+userId);
}
@Override
public void modfiyUser(String userId, String userName) {
System.out.println("UserServiceImpl modfiyUser userId->>"+userId);
}
@Override
public String findUser(String userId) {
System.out.println("UserServiceImpl findUser userId->>"+userId);
return "张山";
}
@Override
public void sayHello(String name) {
System.out.println("你好:"+name);
}
@Override
public int addOperter(int num, int num2) {
return num+num2;
}
}
3.提供一个生成代理'对象的类:LogHandler
public class LogHandler implements InvocationHandler {
private Object targertObject;
public Object newInstance(Object targertObject){
this.targertObject = targertObject;
Class targertClass = targertObject.getClass();
return Proxy.newProxyInstance(targertClass.getClassLoader(), targertClass.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("调用方法"+method.getName());
Object ret = null;
try {
ret = method.invoke(targertObject, args);
System.out.print("成功调用方法:"+method.getName()+";参数为:");
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
} catch (Exception e) {
e.printStackTrace();
System.out.print("调用方法:"+method.getName()+"失败;参数为:");
for (int i = 0; i < args.length; i++) {
System.out.print(args[i]);
}
}
return ret;
}
}
4.编写一个客户端类来使用工厂类生成目标类的代理
public class Client {
public static void main(String[] args) {
Service Service = (Service)new LogHandler().newInstance(new UserServiceImpl());
UserService userService = (UserService)new LogHandler().newInstance(new UserServiceImpl());
userService.addUser("001", "centre");
String name = userService.findUser("002");
System.out.println(name);
int num = Service.addOperter(12, 23);
System.out.println(num);
Service.sayHello("centre");
}
}
三.cglib动态代理
jdk实现动态代理需要实现类通过接口接口定义业务方法,对于没有接口的类,如何实现动态代理?需要cglib了,cglib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLIB动态代理均是实现SpringAop的基础。
1.被代理类,也就是父类,通过字节码技术创建这个类的子类,实现动态代理。
public class SayHello {
public void say(){
System.out.println("hello everyone");
}
}
2.创建代理类
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer(); //CGLIB Enhancer 增强类对象
public Object getProxy(Class clazz){
//设置需要创建子类的类
enhancer.setSuperclass(clazz);
//定义代理逻辑对象为当前类,要求当前对象实现MethodInterceptor方法
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现MethodInterceptor接口方法,代理逻辑方法
public Object interceptor(Object obj,Method method,Object[] args,MethodProxy
methodProxy)throws Throwable {
System.out.println("前置代理");
//通过代理类调用父类中的方法
Object result = methodProxy.invokeSuper(obj,args);
System.out.println("前置代理");
}
}
该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,methodproxy为代理类实例。methodproxy.invokeSuper(obj, args)通过代理类调用父类中的方法。
3.具体实现类
public class DoCGLib {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通过生成子类的方式创建代理类
SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
proxyImp.say();
}
}