java面试题
1、静态代理是啥?有啥缺陷
静态代理是为扩展对象而创建出来的代理对象,静态代理重用性不强。
1、由于静态代理中的代理类是针对某一个类去做代理的,那么假设一个系统中有100个Service,则需要创建100个代理类
2、如果一个Service中有很多方法需要事务(增强动作),发现代理对象的方法中还是有很多重复的代码
动态代理实现的目的和静态代理一样,都是对目标方法进行增强,而且让增强的动作和目标动作分开,达到解耦的目的
动态代理分为JDK的动态代理和cglib动态代理,他俩有略微的差别:cglib动态代理产生的代理对象是目标对象的子类。
package com.cj.study.proxyjdk; public interface PersonService { public String savePerson(); public void updatePerson(); public void deletePerson(); }
package com.cj.study.proxyjdk; public class PersonServiceImpl implements PersonService{ @Override public String savePerson() { System.out.println("添加"); return "保存成功!"; } @Override public void updatePerson() { System.out.println("修改"); } @Override public void deletePerson() { System.out.println("删除"); } }
package com.cj.study.proxyjdk; public class MyTransaction { public void beginTransaction(){ System.out.println("开启事务 "); } public void commit(){ System.out.println("提交事务"); } }
package com.cj.study.proxyjdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class PersonServiceInterceptor implements InvocationHandler{ //目标类 private Object target; //增强类 private MyTransaction myTransaction; //构造函数注入目标类和增强类 public PersonServiceInterceptor(Object target,MyTransaction myTransaction){ this.target = target; this.myTransaction = myTransaction; } //代理类的每一个方法被调用的时候都会调用下边的这个invoke方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { this.myTransaction.beginTransaction(); Object returnValue = method.invoke(this.target, args); this.myTransaction.commit(); return returnValue; } }
package com.cj.study.proxyjdk; import java.lang.reflect.Proxy; import org.junit.Test; public class ProxyTest { @Test public void test(){ Object target = new PersonServiceImpl(); MyTransaction myTransaction = new MyTransaction(); PersonServiceInterceptor interceptor = new PersonServiceInterceptor(target, myTransaction); PersonService personService = (PersonService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),interceptor); String returnValue = (String)personService.savePerson(); System.out.println(returnValue); } }
首先需要导入cglib的jar包:cglib-nodep-2.1_3.jar
package com.cj.study.proxycglib; public interface PersonService { public String savePerson(); public void updatePerson(); public void deletePerson(); }
package com.cj.study.proxycglib; public class PersonServiceImpl implements PersonService{ @Override public String savePerson() { System.out.println("添加"); return "保存成功!"; } @Override public void updatePerson() { System.out.println("修改"); } @Override public void deletePerson() { System.out.println("删除"); } }
package com.cj.study.proxycglib; public class MyTransaction { public void beginTransaction(){ System.out.println("开启事务 "); } public void commit(){ System.out.println("提交事务"); } }
package com.cj.study.proxycglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class PersonServiceInterceptor implements MethodInterceptor{ //目标类 private Object target; //增强类 private MyTransaction myTransaction; //构造函数注入目标类和增强类 public PersonServiceInterceptor(Object target,MyTransaction myTransaction){ this.target = target; this.myTransaction = myTransaction; } public Object createProxy(){ Enhancer enhancer = new Enhancer(); enhancer.setCallback(this); enhancer.setSuperclass(this.target.getClass()); return enhancer.create(); } @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { myTransaction.beginTransaction(); Object returnValue = arg1.invoke(this.target, arg2); myTransaction.commit(); return returnValue; } }
package com.cj.study.proxycglib; import org.junit.Test; public class ProxyTest { @Test public void test(){ Object target = new PersonServiceImpl(); MyTransaction myTransaction = new MyTransaction(); PersonServiceInterceptor interceptor = new PersonServiceInterceptor(target, myTransaction); PersonService personService =(PersonService) interceptor.createProxy(); String returnValue = (String)personService.savePerson(); System.out.println(returnValue); } }
一、简单来说:
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
二、Spring在选择用JDK还是CGLiB的依据:
(1)当Bean实现接口时,Spring就会用JDK的动态代理
(2)当Bean没有实现接口时,Spring使用CGlib是实现
(3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
三、CGlib比JDK快?
(1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
(2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。