1、什么是反射

反射:reflection

类信息 ——> 对象

对象 ——> 类信息

Java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象方法地功能称为反射。


2、Class类

Class类是一切的反射根源

Class类表示什么?
很多的人——可以定义一个Person类(有年龄, 性别, 姓名等)
很多的车——可以定义一个Car类(有发动机, 颜色, 车轮等)
很多的类——Class类(类名, 构造方法, 属性, 方法)

得到Class类的对象有三种方式:
第一种形式: Object类中的getClass()方法
第二种形式: 类.class
第三种形式: 通过Class类的forName方法

  1. public class Dog {
  2. public int type;
  3. private String name;
  4. private int age;
  5. private String color;
  6. private void set(){
  7. System.out.println("set");
  8. }
  9. protected void get(){
  10. System.out.println("get");
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public int getAge() {
  19. return age;
  20. }
  21. public void setAge(int age) {
  22. this.age = age;
  23. }
  24. public String getColor() {
  25. return color;
  26. }
  27. public void setColor(String color) {
  28. this.color = color;
  29. }
  30. @Override
  31. public String toString() {
  32. return "Dog{" +
  33. "name='" + name + '\'' +
  34. ", age=" + age +
  35. ", color='" + color + '\'' +
  36. '}';
  37. }
  38. public Dog() {
  39. }
  40. public Dog(String name, int age, String color) {
  41. this.name = name;
  42. this.age = age;
  43. this.color = color;
  44. }
  45. }
  1. public class ReflectionDemo {
  2. /**
  3. * 获取Class对象的三种形式
  4. */
  5. @Test
  6. public void test1(){
  7. //通过对象的getClass()方法
  8. Dog dog = new Dog("wangwang",4,"白色");
  9. Class aClass = dog.getClass(); //字节码
  10. //通过类.class
  11. Class dogClass = Dog.class;
  12. //通过Class.forName方法
  13. try {
  14. Class aClass1 = Class.forName("com.vince.Dog");
  15. } catch (ClassNotFoundException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. }

使用Class类进行对象的实例化操作

调用无参构造进行实例化:

public T newInstance() throws InstantiationException,IllegalAccessException

调用有参构造进行实例化:

public Constructor<?>[] getConstructors() throws SecurityException

获取类、方法、属性

  1. import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
  2. import org.junit.Test;
  3. import java.lang.reflect.*;
  4. public class ReflectionDemo {
  5. //获取所有的属性
  6. @Test
  7. public void test4(){
  8. Class<Dog> dogClass = Dog.class;
  9. //获取非私有属性
  10. Field[] fields = dogClass.getFields();
  11. //System.out.println(fields.length);
  12. //获取所有属性(包括私有属性)
  13. Field[] declaredFields = dogClass.getDeclaredFields();
  14. //System.out.println(declaredFields.length);
  15. for (int i = 0; i < declaredFields.length; i++) {
  16. int modifiers = declaredFields[i].getModifiers();
  17. System.out.println(Modifier.toString(modifiers)+ " "+declaredFields[i].getType()+" "+declaredFields[i].getName());
  18. }
  19. }
  20. //获取所有构造方法
  21. @Test
  22. public void test3(){
  23. Class<Dog> dogClass = Dog.class;
  24. Constructor<?>[] constructors = dogClass.getConstructors();
  25. for (int i = 0; i < constructors.length; i++) {
  26. System.out.println(constructors[i].getName());
  27. System.out.println(constructors[i].getParameterCount());
  28. }
  29. try {
  30. //获取一个指定的构造方法
  31. Constructor<Dog> constructor = dogClass.getConstructor(String.class, int.class, String.class);
  32. //调用带参数的构造器来实例化对象
  33. Dog dog = constructor.newInstance("小白", 5, "白色");
  34. } catch (NoSuchMethodException e) {
  35. e.printStackTrace();
  36. } catch (IllegalAccessException e) {
  37. e.printStackTrace();
  38. } catch (InstantiationException e) {
  39. e.printStackTrace();
  40. } catch (InvocationTargetException e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. /**
  45. * 通过反射来实例化对象
  46. */
  47. public void test2(){
  48. Class<Dog> dogClass = Dog.class;
  49. try {
  50. //通过Class对象实例化类对象,调用了默认无参的构造方法
  51. Dog dog = (Dog) dogClass.newInstance();
  52. } catch (InstantiationException e) {
  53. e.printStackTrace();
  54. } catch (IllegalAccessException e) {
  55. e.printStackTrace();
  56. }
  57. }
  58. /**
  59. * 获取Class对象的三种形式
  60. */
  61. @Test
  62. public void test1(){
  63. //通过对象的getClass()方法
  64. Dog dog = new Dog("wangwang",4,"白色");
  65. Class aClass = dog.getClass(); //字节码
  66. //通过类.class
  67. Class dogClass = Dog.class;
  68. //通过Class.forName方法
  69. try {
  70. Class aClass1 = Class.forName("com.vince.Dog");
  71. } catch (ClassNotFoundException e) {
  72. e.printStackTrace();
  73. }
  74. }
  75. }

3、通过Class类取得类信息

取得类所在的包
public Package getPackage() //得到一个类所在的包
public String getName() //得到名字

取得一个类中的全部方法
public Method[] getMethods()
public int getModifiers() //Modifier.toString(mod); // 还原修饰符
public Class<?> getReturnType()
public Class<?>[] getParameterTypes()
public Class<?>[] getExceptionTypes()
public static String toString(int mod)

取得一个类中的全部属性
public Field[] getFields()
public Field[] getDeclaredFields()
public Class<?> getType()
public int getModifiers()
public String getName()


4、通过Class类调用属性或方法

调用类中的方法
调用类中的方法, 传入实例化对象, 以及具体的参数内容
public Object invoke(Object obj,Object… args)

直接调用属性
取得属性
public Object get(Object obj)
//设置属性, 等同于使用“ =” 完成操作
public void set(Object obj,Object value)
//让属性对外部可见
public void setAccessible(boolean flag)

  1. import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
  2. import org.junit.Test;
  3. import java.lang.reflect.*;
  4. public class ReflectionDemo {
  5. @Test
  6. public void test5(){
  7. Dog dog = new Dog("wangwang",4,"白色");
  8. Class<Dog> dogClass = Dog.class;
  9. //获取类的包名
  10. Package aPackage = dogClass.getPackage();
  11. //System.out.println(aPackage.getName());
  12. //获取公共的方法,包括继承的公有方法
  13. Method[] methods = dogClass.getMethods();
  14. for (int i = 0; i < methods.length; i++) {
  15. System.out.println(methods[i]);
  16. if (methods[i].getName().equals("toString")){
  17. try {
  18. String s = (String)methods[i].invoke(dog);
  19. System.out.println(s);
  20. } catch (IllegalAccessException e) {
  21. e.printStackTrace();
  22. } catch (InvocationTargetException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }
  27. System.out.println("---------------");
  28. //访问私有方法,获取到本类中定义的所有方法(不包括父类)
  29. Method[] declaredMethods = dogClass.getDeclaredMethods();
  30. for (int i = 0; i < declaredMethods.length; i++) {
  31. System.out.println(declaredMethods[i]);
  32. if (declaredMethods[i].getName().equals("set")){
  33. //设置 私有方法可以被访问(去除访问修饰符的检查)
  34. declaredMethods[i].setAccessible(true);
  35. try {
  36. declaredMethods[i].invoke(dog);
  37. } catch (IllegalAccessException e) {
  38. e.printStackTrace();
  39. } catch (InvocationTargetException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43. }
  44. }
  45. }

5、动态代理

所谓动态代理, 即通过代理类: Proxy的代理, 接口和实现类之间可以不直接发生联系, 而可以在运行期(Runtime) 实现动态关联。
java动态代理主要是使用java.lang.reflect包中的两个类。

InvocationHandler类
public Object invoke(Object obj,Method method,Object[] obs)
其中第一个参数 obj 指的是代理类, method是被代理的方法, obs是指被代理的方法的参数组。 此方法由代理类来实现。

Proxy类
protected Proxy(InvocationHandler h);
static Class getProxyClass(ClassLoader loader,Class[] interfaces);
static Object newProxyInstance(ClassLoader loader,Class[]interfaces,InvocationHandlerh);
动态代理其实是在运行时生成class, 所以, 我们必须提供一组interface, 然后告诉他class已经实现了这些interface, 而且在生成Proxy的时候, 必须给他提供一个handler, 让他来接管实际的工作。

Subject

  1. package com.vince.proxy;
  2. public interface Subject {
  3. public void shopping();
  4. }

Hotel

  1. package com.vince.proxy;
  2. public interface Hotel {
  3. public void reserve();
  4. }

Person

  1. package com.vince.proxy;
  2. public class Person implements Subject,Hotel{
  3. @Override
  4. public void shopping() {
  5. System.out.println("付款,买到心仪的衣服");
  6. }
  7. @Override
  8. public void reserve() {
  9. System.out.println("付预定款,打飞的前往目的地");
  10. }
  11. }

CreatProxy

  1. package com.vince.proxy;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. /**
  6. * 用于动态生成一个代理对象
  7. */
  8. public class CreateProxy implements InvocationHandler {
  9. private Object target;//被代理的对象
  10. //用于创建代理对象的方法
  11. public Object create(Object target){
  12. this.target = target;
  13. Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);
  14. return proxy;
  15. }
  16. /**
  17. * 代理对象要执行的方法
  18. * @param proxy 代理类对象
  19. * @param method 被代理对象的方法
  20. * @param args 被代理对象方法的参数
  21. * @return
  22. * @throws Throwable
  23. */
  24. @Override
  25. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  26. System.out.println("上海外寻找客户需要的产品...");
  27. System.out.println("跟客户确认产品");
  28. method.invoke(target,args);
  29. System.out.println("完成本次海淘");
  30. return null;
  31. }
  32. }

TestDemo

  1. package com.vince.proxy;
  2. import org.junit.Test;
  3. public class TestDemo {
  4. @Test
  5. public void testProxy(){
  6. CreateProxy cp = new CreateProxy();//用来创建代理对象的对象
  7. Hotel person = new Person();
  8. Hotel proxy = (Hotel) cp.create(person);
  9. //proxy.shopping();//调用invoke
  10. proxy.reserve();
  11. }
  12. }

6、类加载器原理分析与实现

1、 类的加载过程

JVM将类加载过程分为三个步骤: 装载(Load) , 链接(Link) 和初始化(Initialize)链接又分为三个步骤, 如下图所示:

12、反射与内省 - 图1

1)装载: 查找并加载类的二进制数据;

2)链接:

  1. 验证: 确保被加载类的正确性;
  2. 准备: 为类的静态变量分配内存, 并将其初始化为默认值;
  3. 解析: 把类中的符号引用转换为直接引用;

3)初始化: 为类的静态变量赋予正确的初始值;

2、 类的初始化, 类什么时候才被初始化:

  1. 创建类的实例, 也就是new一个对象
  2. 访问某个类或接口的静态变量, 或者对该静态变量赋值
  3. 调用类的静态方法
  4. 反射(Class.forName(“com.vince.Dog”))
  5. 初始化一个类的子类(会首先初始化子类的父类)
  6. JVM启动时标明的启动类, 即文件名和类名相同的那个类

3、 类的加载:

指的是将类的.class文件中的二进制数据读入到内存中, 将其放在运行时数据区的方法区内, 然后在堆区创建一个这个类的Java.lang.Class对象, 用来封装类在方法区类的对象


7、JavaBean

1、JavaBean概念

Bean理解为组件意思, JavaBean就是Java组件, 在广泛的理解就是一个类, 对于组件来说, 关键在于要具有“ 能够被IDE构建工具侦测其属性和事件” 的能力, 通常在Java中 。

2、JavaBean命名规则

  1. 对于一个名称为xxx的属性, 通常你要写两个方法: getXxx()和setXxx()。 任何浏览这些方法的工具, 都会把get或set后面的第一个字母自动转换为小写。
  2. 对于布尔型属性, 可以使用以上get和set的方式, 不过也可以把get替换成is。
  3. Bean的普通方法不必遵循以上的命名规则, 不过它们必须是public的。
  4. 对于事件, 要使用Swing中处理监听器的方式。 如addWindowListener、removeWindowListener

BeanUtils工具类: http://apache.org/

EMP

  1. package com.vince.bean;
  2. /**
  3. */
  4. public class Emp {
  5. private String name;
  6. private int age;
  7. private int salary;
  8. public String getInfo(){
  9. return "name="+name+",sage="+age+",salray="+salary;
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. public int getAge() {
  18. return age;
  19. }
  20. public void setAge(int age) {
  21. this.age = age;
  22. }
  23. public int getSalary() {
  24. return salary;
  25. }
  26. public void setSalary(int salary) {
  27. this.salary = salary;
  28. }
  29. }

BeanTest

  1. package com.vince.bean;
  2. import org.apache.commons.beanutils.BeanUtils;
  3. import org.junit.Test;
  4. import java.lang.reflect.InvocationTargetException;
  5. /**
  6. */
  7. public class BeanTest {
  8. @Test
  9. public void test(){
  10. //从客户端获取到的数据是这样的
  11. String name = "bin";
  12. String age = "18";
  13. String salary = "20000";
  14. Emp emp = new Emp();
  15. try {
  16. BeanUtils.setProperty(emp,"name",name);
  17. BeanUtils.setProperty(emp,"age",age); //实现强转
  18. BeanUtils.setProperty(emp,"salary",salary);
  19. } catch (IllegalAccessException e) {
  20. e.printStackTrace();
  21. } catch (InvocationTargetException e) {
  22. e.printStackTrace();
  23. }
  24. System.out.println(emp.getInfo());
  25. }
  26. }

12、反射与内省 - 图2


8、内省基本概念

内省(Introspector)是Java 语言对 Bean 类属性、 事件的一种缺省处理方法。 例如类 A 中有属性name, 那我们可以通过getName,setName 来得到其值或者设置新的值。

通过 getName/setName 来访问 name 属性, 这就是默认的规则

Java 中提供了一套 API 用来访问某个属性的 getter/setter 方法, 通过这些 API 可以使你不需要了解这个规则, 这些 API 存放于包 java.beans 中, 一般的做法是通过类 Introspector 的getBeanInfo方法 来获取某个对象的 BeanInfo 信息, 然后通过 BeanInfo 来获取属性的描述器(PropertyDescriptor), 通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。

1、 Introspector类:
Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、 事件和方法的知识提供了一个标准方法。
static BeanInfo getBeanInfo(Class<?> beanClass)在 Java Bean 上进行内省, 了解其所有属性、 公开的方法和事件。

2、 BeanInfo类:
该类实现此 BeanInfo 接口并提供有关其 bean 的方法、 属性、 事件等显式信息。
MethodDescriptor[] getMethodDescriptors()
获得 beans MethodDescriptor。
PropertyDescriptor[] getPropertyDescriptors()
获得 beans PropertyDescriptor。
Properties 属性文件工具类的使用

3、 PropertyDescriptor 类:
PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
Method getReadMethod()
获得应该用于读取属性值的方法。
Method getWriteMethod()
获得应该用于写入属性值的方法。

4、 MethodDescriptor 类:
MethodDescriptor 描述了一种特殊方法,
即 Java Bean 支持从其他组件对其进行外部访问。
Method getMethod()
获得此 MethodDescriptor 封装的方法。

config.properties

  1. bean.name=com.vince.introspector.Config
  2. bean.username=admin
  3. bean.password=123
  4. bean.url=http://www.163.com

Config

  1. package com.vince.introspector;
  2. /**
  3. */
  4. public class Config {
  5. private String username;
  6. private String password;
  7. private String url;
  8. public String getUsername() {
  9. return username;
  10. }
  11. public void setUsername(String username) {
  12. this.username = username;
  13. }
  14. public String getPassword() {
  15. return password;
  16. }
  17. public void setPassword(String password) {
  18. this.password = password;
  19. }
  20. public String getUrl() {
  21. return url;
  22. }
  23. public void setUrl(String url) {
  24. this.url = url;
  25. }
  26. public Config(String username, String password, String url) {
  27. this.username = username;
  28. this.password = password;
  29. this.url = url;
  30. }
  31. public Config() {
  32. }
  33. @Override
  34. public String toString() {
  35. return "Config{" +
  36. "username='" + username + '\'' +
  37. ", password='" + password + '\'' +
  38. ", url='" + url + '\'' +
  39. '}';
  40. }
  41. }

BeanFactory

  1. package com.vince.introspector;
  2. import com.sun.corba.se.impl.ior.WireObjectKeyTemplate;
  3. import java.beans.BeanInfo;
  4. import java.beans.IntrospectionException;
  5. import java.beans.Introspector;
  6. import java.beans.PropertyDescriptor;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.lang.reflect.InvocationTargetException;
  10. import java.lang.reflect.Method;
  11. import java.util.Properties;
  12. /**
  13. * 通过内省的API来装配一个Bean对象,Bean对象的值是通过配置文件中来获取
  14. * 目的是为了提高维护性
  15. */
  16. public class BeanFactory {
  17. private static Properties prop = new Properties();
  18. //使用静态代码块读取配置文件
  19. static {
  20. InputStream in = Thread.currentThread().getContextClassLoader()
  21. .getResourceAsStream("com/vince/introspector/config.properties");
  22. try {
  23. prop.load(in);
  24. } catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. /**
  29. * 获取一个Bean
  30. * @param name
  31. * @return
  32. */
  33. public static Object getBean(String name){
  34. Object bean = null;
  35. String beanName = prop.getProperty(name);
  36. try {
  37. Class<?> aClass = Class.forName(beanName);
  38. bean = aClass.newInstance();
  39. //通过类信息获取javaBean的描述信息
  40. BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
  41. //通过javaBean描述信息,获取该类的所有属性描述器
  42. PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
  43. for (int i = 0; i < propertyDescriptors.length; i++) {
  44. String propertyName = propertyDescriptors[i].getName();
  45. Method writeMethod = propertyDescriptors[i].getWriteMethod();
  46. if("username".equals(propertyName)) {
  47. //调用属性的set方法
  48. writeMethod.invoke(bean,prop.getProperty("bean.username"));
  49. }else if ("password".equals(propertyName)){
  50. writeMethod.invoke(bean,prop.getProperty("bean.password"));
  51. }else if("url".equals(propertyName)){
  52. writeMethod.invoke(bean,prop.getProperty("bean.url"));
  53. }
  54. }
  55. } catch (ClassNotFoundException e) {
  56. e.printStackTrace();
  57. } catch (IntrospectionException e) {
  58. e.printStackTrace();
  59. } catch (IllegalAccessException e) {
  60. e.printStackTrace();
  61. } catch (InstantiationException e) {
  62. e.printStackTrace();
  63. } catch (InvocationTargetException e) {
  64. e.printStackTrace();
  65. }
  66. return bean;
  67. }
  68. }

BeanTest

  1. package com.vince.introspector;
  2. import org.junit.Test;
  3. /**
  4. */
  5. public class BeanTest {
  6. @Test
  7. public void getBeanTest(){
  8. Config bean = (Config)BeanFactory.getBean("bean.name");
  9. System.out.println(bean);
  10. }
  11. }

9、初探:理解可配置的AOP框架

补充知识:

  1. AOP的概念: Aspect Oriented Programming(面向切面编程)
  2. 可配置 AOP框架实现

AOP使用场景
AOP用来封装横切关注点, 具体可以在下面的场景中使用:

  • 权限
  • 缓存
  • 错误处理
  • 调试
  • 记录跟踪
  • 持久化
  • 同步
  • 事务
  • 。。 。

处理非主流业务,将主流业务与非主流业务完全分开

12、反射与内省 - 图3

IManager

  1. package com.vince.aop;
  2. public interface IManager {
  3. public void add(String item);
  4. }

IManagerImpl

  1. package com.vince.aop;
  2. import java.util.ArrayList;
  3. public class IManagerImpl implements IManager {
  4. private ArrayList<String> list = new ArrayList<>();
  5. @Override
  6. public void add(String item) {
  7. // System.out.println("add start "+ System.currentTimeMillis());
  8. list.add(item);
  9. System.out.println(item);
  10. // System.out.println("add end "+ System.currentTimeMillis());
  11. }
  12. }

Advice

  1. package com.vince.aop;
  2. /**
  3. * 通知
  4. */
  5. public interface Advice {
  6. public void beforeAdvice();
  7. public void afterAdvice();
  8. }

LogAdvice

  1. package com.vince.aop;
  2. /**
  3. * 切面的实现类
  4. */
  5. public class LogAdvice implements Advice{
  6. @Override
  7. public void beforeAdvice() {
  8. System.out.println("start time:"+System.currentTimeMillis());
  9. }
  10. @Override
  11. public void afterAdvice() {
  12. System.out.println("end time:"+System.currentTimeMillis());
  13. }
  14. }

bean.properties

  1. bean.target=com.vince.aop.IManagerImpl
  2. bean.advice=com.vince.aop.LogAdvice
  3. bean=com.vince.aop.ProxyFactoryBean

ProxyFactoryBean

  1. package com.vince.aop;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. import java.lang.reflect.Proxy;
  5. public class ProxyFactoryBean implements InvocationHandler {
  6. private Object target;
  7. private Advice advice;
  8. public Object getProxy(){
  9. Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
  10. return proxy;
  11. }
  12. @Override
  13. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  14. advice.beforeAdvice();
  15. Object obj = method.invoke(target, args);
  16. advice.afterAdvice();
  17. return obj;
  18. }
  19. public Object getTarget() {
  20. return target;
  21. }
  22. public void setTarget(Object target) {
  23. this.target = target;
  24. }
  25. public Advice getAdvice() {
  26. return advice;
  27. }
  28. public void setAdvice(Advice advice) {
  29. this.advice = advice;
  30. }
  31. }

BeanFactory

  1. package com.vince.aop;
  2. import java.beans.BeanInfo;
  3. import java.beans.IntrospectionException;
  4. import java.beans.Introspector;
  5. import java.beans.PropertyDescriptor;
  6. import java.io.IOException;
  7. import java.io.InputStream;
  8. import java.lang.reflect.InvocationTargetException;
  9. import java.lang.reflect.Method;
  10. import java.util.Properties;
  11. /**
  12. * AOP框架的简单实现
  13. */
  14. public class BeanFactory {
  15. Properties prop = new Properties();
  16. public BeanFactory(InputStream in){
  17. try {
  18. prop.load(in);
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. /**
  24. * 获取一个bean实例
  25. * @param name
  26. * @return
  27. */
  28. public Object getBean(String name){
  29. String className = prop.getProperty(name);
  30. Object bean = null;
  31. try {
  32. //获取ProxyFactoryBean的class对象
  33. Class<?> aClass = Class.forName(className);
  34. bean = aClass.newInstance();//实例化对象
  35. //根据配置文件实例化target和advice对象
  36. Object target = Class.forName(prop.getProperty(name + ".target")).newInstance();
  37. Object advice = Class.forName(prop.getProperty(name + ".advice")).newInstance();
  38. //通过内省实现对 ProxyFactoryBean的属性赋值
  39. BeanInfo beanInfo = Introspector.getBeanInfo(aClass);
  40. PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
  41. for(PropertyDescriptor pd: propertyDescriptors){
  42. String propertyName = pd.getName();
  43. Method writeMethod = pd.getWriteMethod();
  44. if("target".equals(propertyName)){
  45. writeMethod.invoke(bean,target);
  46. }else if("advice".equals(propertyName)){
  47. writeMethod.invoke(bean,advice);
  48. }
  49. }
  50. } catch (ClassNotFoundException e) {
  51. e.printStackTrace();
  52. } catch (IllegalAccessException e) {
  53. e.printStackTrace();
  54. } catch (InstantiationException e) {
  55. e.printStackTrace();
  56. } catch (IntrospectionException e) {
  57. e.printStackTrace();
  58. } catch (InvocationTargetException e) {
  59. e.printStackTrace();
  60. }
  61. return bean;
  62. }
  63. }

AOPTest

  1. package com.vince.aop;
  2. import org.junit.Test;
  3. import java.io.InputStream;
  4. public class AOPTest {
  5. @Test
  6. public void test(){
  7. //1读取配置 文件
  8. InputStream in = Thread.currentThread().getContextClassLoader()
  9. .getResourceAsStream("com/vince/aop/bean.properties");
  10. //2创建Bean的工厂对象
  11. BeanFactory beanFactory = new BeanFactory(in);
  12. //3获取代理对象
  13. ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) beanFactory.getBean("bean");
  14. IManager proxy = (IManager) proxyFactoryBean.getProxy();
  15. proxy.add("我是一只猫");
  16. }
  17. }

10、单例模式优化

  1. 使用同步保正线程安全 synchronized
  2. 使用volatile关键字
    volatile提醒编译器它后面所定义的变量随时都有可能改变, 因此编译后的程序每次需要存储或读取这个变量的时候, 都会直接从变量地址中读取数据。 如果没有volatile关键字, 则编译器可能优化读取和存储, 可能暂时使用寄存器中的值, 如果这个变量由别的程序更新了的话,将出现不一致的现象。
  3. 防止反射调用私有构造方法
  4. 让单例类序例化安全
  1. package com.vince.singleton;
  2. import java.io.Serializable;
  3. /**
  4. * 单例模式
  5. * 1、多线程访问的安全问题
  6. * 2、加上volatile关键字保证变量的一致性
  7. * 3、防止反射调用私有构造方法
  8. * 4、让单例类可以被序列化
  9. */
  10. public class Singleton implements Serializable {
  11. private volatile static Singleton singleton = null;
  12. private Singleton(){
  13. if (singleton!=null){
  14. throw new RuntimeException("此类对象为单例模式,已经被实例化了");
  15. }
  16. }
  17. public static Singleton getInstance() {
  18. if (singleton==null) {
  19. synchronized (Singleton.class) {
  20. if (singleton == null) {
  21. singleton = new Singleton();
  22. }
  23. }
  24. }
  25. return singleton;
  26. }
  27. }