1、动态代理的几种方式

Java主要有两种代理,JDK和Cglib动态代理。先看JDK代理实例如下:

JDK创建代理有一个限制,即它只能为接口创建代理实例。举个例子如下:

public interface Advice {
	void beforeMethod();
	void afterMethod();
}

public class TimeAdvice implements Advice {
	long startTime;
	long endTime;

	public void beforeMethod() {
		startTime = System.nanoTime(); // 获取开始时间
		System.out.println("开始计算程序运行时间" + startTime);
	}

	public void afterMethod() {
		endTime = System.nanoTime(); // 获取结束时间
		System.out.println("计算程序运行时间: " + (endTime - startTime) + "ns");
	}
}
public interface SalaryInterface {
    public void doSalary();
}
public class Salary  implements SalaryInterface{
    public void doSalary() {
          System.out.println("进行薪资计算的逻辑处理");
      }
}

  

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
 * 每一个代理实例都必须指定一个调用处理器,代理对象调用方法时,
 * 该方法会指派到调用处理器的invoke()中去。代理的方法封装成
 * invoke中的method对象,其中的参数封装成Object[].
 */
public class MyProxy implements InvocationHandler{  

     private Object obj;   // 希望被代理的对象
     private Advice advice;  

    // 绑定代理对象
    public Object bind(Object obj, Advice advice) {
        this.obj = obj;
        this.advice = advice;
        return Proxy.newProxyInstance(
                obj.getClass().getClassLoader(), // 类加载器
                obj.getClass().getInterfaces(),  // 创建目标类所需要使用的一组接口
                this  // 一个实现InvocationHandler的实例,用来整合横切与业务逻辑
            );
        }  

    /*
     * 实现代理
     * method为方法名,args为代理实例某一方法的入参数组,而obj为所属的实例对象
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
            advice.beforeMethod();
            result = method.invoke(obj, args);
            advice.afterMethod();
        } catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }
}
public class Bootstrap {

	public static void main(String[] args) {

        Advice advice = new TimeAdvice();
        SalaryInterface p = new Salary();
        // Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象
        MyProxy proxy = new MyProxy();  

        SalaryInterface y = (SalaryInterface)proxy.bind(p, advice);
        y.doSalary(); // 相当于调用proxy.invoke(proxy, "doSalary, null);
	}
}
开始计算程序运行时间43041762316001
进行薪资计算的逻辑处理
计算程序运行时间: 882610ns

  

CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。  

CGGlib创建的代理对象要比JDK的性能高很多,但是创建时所花费的时间却比JDK动态代理要多。所以对于singleton的代理对象或者具有实例池的代码,由于无须频繁创建代码对象,用CGLib比较合适。也就是生命周期长的实例用CGLib比较合适。

/**
 * 使用cglib动态代理
 */
public class Cglib implements MethodInterceptor {
    private Object target;
    long startTime;
   	long endTime;

    /**
     * 创建代理对象
     */
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());  // 设置需要创建子类的类
        enhancer.setCallback(this);   // 回调方法
        return enhancer.create();     // 通过字节码技术动态创建子类实例
    }  

    @Override
    // 回调方法 ,拦截所有的父类方法调用
    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
    	startTime = System.nanoTime(); // 获取开始时间
		System.out.println("开始计算程序运行时间" + startTime);
        Object result = proxy.invokeSuper(obj, args);   // 通过代码类调用父类中的方法
        endTime = System.nanoTime();   // 获取结束时间
		System.out.println("计算程序运行时间: " + (endTime - startTime) + "ns");
        return result;
    }  

}

  

/*
 * 采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截
 * 所有父类方法的调用,并顺势织入横切逻辑
 *
 * singletom的代理对象或者具有实例池的代理,因为无须频繁创建代理对象,比较适合用CGLib动态代理技术
 *
 * 由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行代理
 */
public class TestCglib {

    public static void main(String[] args) {
        Cglib cglib=new Cglib();
        Salary salary=(Salary)cglib.getInstance(new Salary());
        salary.doSalary();
    }
}

2、Spring AOP(Aspect Oriented Programming面向切面编程)与IoC(Inverse of Control控制反转)的实现

Spring AOP主要就是通过动态代理来实现,而Ioc是通过反射来实现,将创建对象和对象之间的依赖管理交给IoC容器来做,完成对象之间的解耦。

举个反射的例子,如下:

public class Car {
	private String brand;
	private String color;
	private int maxSpeed;

	public Car() {
		System.out.println("init car!!");
	}

	public Car(String brand, String color, int maxSpeed) {
		this.brand = brand;
		this.color = color;
		this.maxSpeed = maxSpeed;
	}

	public void introduce() {
		System.out.println("brand:" + brand + ";color:" + color + ";maxSpeed:" + maxSpeed);
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public int getMaxSpeed() {
		return maxSpeed;
	}

	public void setMaxSpeed(int maxSpeed) {
		this.maxSpeed = maxSpeed;
	}
}
public class ReflectTest {

	public static Car initByDefaultConst() throws Throwable {
		// loadClass()方法必须使用全额限定名
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		// 每一个类在JVM中都拥有一个对应的java.lang.Class对象,用来描述类结构信息
//		Class clazz = loader.loadClass("reflect.Car");
		Class clazz = Class.forName("reflect.Car");
		Constructor cons = clazz.getDeclaredConstructor((Class[]) null);
		Car car = (Car) cons.newInstance();

		Method setBrand = clazz.getMethod("setBrand", String.class);
		setBrand.invoke(car, "红旗CA72");
		Method setColor = clazz.getMethod("setColor", String.class);
		setColor.invoke(car, "黑色");
		Method setMaxSpeed = clazz.getMethod("setMaxSpeed", int.class);
		setMaxSpeed.invoke(car, 200);
		return car;
	}

	public static Car initByParamConst() throws Throwable {
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		Class clazz = loader.loadClass("reflect.Car");
		Constructor cons = clazz.getDeclaredConstructor(new Class[] { String.class, String.class, int.class });
		Car car = (Car) cons.newInstance(new Object[] { "吉利TOPMIX", "绿色", 120 });
		return car;
	}

	public static void main(String[] args) throws Throwable {
		 Car car1 = initByDefaultConst();
		 Car car2 = initByParamConst();
		 car1.introduce();
		 car2.introduce();
	}
}

  

init car!!
brand:红旗CA72;color:黑色;maxSpeed:200
brand:吉利TOPMIX;color:绿色;maxSpeed:120

每一个类在JVM中都拥有一个对应的java.lang.Class对象,它提供了类结构信息的描述。数组、枚举、注解甚至void都有对应的Class对象。可以从Class对象中获取构造函数、成员变量、方法等类元素的反射对象,并以编程的方式通过这些反射对目标类对象进行操作。

  

3、Spring的事务实现原理

  

Java面试04|Spring框架的更多相关文章

  1. Java 横向技术 Spring框架【笔记】

    Java横向技术 spring框架[笔记] Spring 的两大特性是什么? AOP(Aspect Oriented Programming,面向切面编程)与 IOC(Inverse of Contr ...

  2. Java开发工程师(Web方向) - 04.Spring框架 - 第3章.AOP技术

    第3章--AOP技术 Spring框架 - AOP概述 笔记https://my.oschina.net/hava/blog/758873Spring框架 - AOP使用 笔记https://my.o ...

  3. Java开发工程师(Web方向) - 04.Spring框架 - 第2章.IoC容器

    第2章.IoC容器 IoC容器概述 abstract: 介绍IoC和bean的用处和使用 IoC容器处于整个Spring框架中比较核心的位置:Core Container: Beans, Core, ...

  4. Java开发工程师(Web方向) - 04.Spring框架 - 第1章.Spring概述

    第1章.Spring概述 Spring概述 The Spring Framework is a lightweight solution and a potential one-stop-shop f ...

  5. Java开发工程师(Web方向) - 04.Spring框架 - 期末测试

    Spring框架客观题 Spring框架编程题 http://blog.csdn.net/sinoacc/article/details/51702458 1 (25分) 假设有如下数据表: crea ...

  6. Java开发工程师(Web方向) - 04.Spring框架 - 第4章.数据访问

    第4章--数据访问 Spring JDBC DAO (Data Access Object) 实现数据访问相关接口(接口和实现分离) ORM (Object Relation Mapping) 对象关 ...

  7. [Java面试五]Spring总结以及在面试中的一些问题.

    1.谈谈你对spring IOC和DI的理解,它们有什么区别? IoC Inverse of Control 反转控制的概念,就是将原本在程序中手动创建UserService对象的控制权,交由Spri ...

  8. Java面试之五大框架的理解

    五大框架(springMVC,struts2,spring,mybatis,hibernate) 说说你对springMVC框架的理解? 简要口述(如果感觉说的少可以在完整答案里面挑几条说) Spri ...

  9. 【Java】关于Spring框架的总结 (三)

    前文对 Spring IoC 和 Spring AOP 的实现方法进行了整合.如果有不明白的或有质疑的地方可以评论出来,一起探讨问题,帮助别人也是帮助自己!本文探讨的中心主要放在 Spring 的注解 ...

随机推荐

  1. C语言strstr()函数:返回字符串中首次出现子串的地址

    今天又学到了一个函数 头文件:#include <string.h> strstr()函数用来检索子串在字符串中首次出现的位置,其原型为:    char *strstr( char *s ...

  2. systemd的命令systemctl set-property testSpeed CPUQuota=10%

    总结 systemd 的资源限制一般要写到unit文件中,但是,现在测试发现会有 被值被覆盖的现象:经过排查发现是,没有 使用systemd的接口,凡是使用echo "" > ...

  3. eclipse开发velocity实例(初学)

    开发环境         Eclipse Java EE IDE for Web Developers.(Version: Helios Service Release 1) jdk1.6.0_07 ...

  4. JDK中的插入排序

    算法 有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法--插入排序法,插入排序的基本操作就是将一个数据插入到已经排好 ...

  5. JSP userBean setProperty getProperty指令使用

    JSP userBean setProperty getProperty指令使用 javaBean的属性取决于get/set方法,而不是真实的属性名称. jsp文件: <%@ page lang ...

  6. Node.js理解

    JavaScript单线程的误解 在我接触JavaScript(无论浏览器还是NodeJS)的时间里,总是遇到有朋友有多线程的需求.而在NodeJS方面,有朋友甚至直接说到,NodeJS是单线程的,无 ...

  7. JTable 的使用

    JTable是Swing编程中的一种控件. 一.创建表格控件的各种方式:1) 调用无参构造函数. JTable table = new JTable(); 2) 以表头和表数据创建表格. Object ...

  8. gulp实时编译less,压缩合并requirejs模块文件

    gulp的使用命令简单,就几个,gulp的简单使用教材可以参考一点的gulp使用教材(http://www.ydcss.com/archives/18). 下面就简单的介绍这些命令如何互相配合的完成前 ...

  9. webAppbuilder微件使用教程1 快速入门

    by 李远祥 webAppbuilder是arcgis portal 和arcgis.com 上用来配置应用程序的利器.合理利用webAppbuilder的微件功能,可以实现应用程序的零代码定制,并能 ...

  10. CSS 专业技巧

    使用CSS复位 CSS复位可以在不同的浏览器上保持一致的样式风格.您可以使用CSS reset 库Normalize等,也可以使用一个更简化的复位方法: * { box-sizing: border- ...