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%左右。

 

posted on 2021-02-19 17:51  清浊  阅读(30)  评论(0编辑  收藏  举报