SpringIOC理解
IOC被称之为控制反转,什么是控制反转呢?
例子:在没有Spring之前,我们创建对象的方式为 new 具体对象();
假设 new User(); 而User的构造方法所需参数只有一个UserInfo类;
public class User {
private UserInfro userInfro;
public User(UserInfro userInfro) {
this.userInfro = userInfro;
}
}
此时创建一个User对象需要先创建一个UserInfo对象
User user=new User(new UserInfro);
而IOC干了干啥呢?
就是它自己创建了这个User对象(在项目启动过程中);
不只各位有没有发现在使用ssm或ssh整合的项目中,我需要一个对象时,用@Autowired或@Resource注解就能直接获得,没有关心该对象与其他对象的关系;
这就是Spring所提供的IOC为我们做的事情;
在启动项目过程中Spring会我们自动去找类与类之间的依赖关系,我们需要的时候直接获取就可以得到,省略了创建对象所需的步骤;
而IOC的底层是DI(依赖注入),而DI依赖于Java的反射机制;
Java的反射机制
什么是Java的反射机制
动态获取类的信息以及动态调用对象的方法称为Java的反射(Reflection)机制。反射提供了封装程序集、模块和类型的对象。在Java运行时环境中,对于任意一个类的对象,可以通过反射获取这个类的信息。(直接copy的)
说白话就是能在运行期间获得类的方法 构造函数 变量等;
在学习反射机制之前,提问一个问题?
假设有一个类中有某个方法 被private修饰,那么该方法能被其他类访问吗?
在没有接触Java的反射机制之前,我的答案可能与大部分人的答案相同,那就是不能。
毕竟在java关键字中三个修饰符
private:只允许本类访问
protected:只允许该包下的类访问
public:公共方法 ,所有类皆可以访问
而在·Java的反射机制中却可以实现对private 方法 或变量的获取(不知道你们哭了没,反正我感觉被骗了)
现在开始学习Java的反射机制;
所用到的类User类
public class User {
public User() {
}
public String getAge01(String u){
System.out.println("getAge01"+u+"年龄为12岁");
return null;
}
private String getAge02(){
System.out.println("getAge02年龄为12岁");
return null;
}
}
User类中包含一个空的构造函数,一个公共的方法,一个私有的方法;
1.首先通过反射获取到指定的类。
定义一个main函数:
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<?> user = Class.forName("com.example.User");
System.out.println(user);
}
打印日志为:class com.example.User
2.创建此实例对象
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
Class<?> clazz = Class.forName("com.example.User");
User user = (User) clazz.newInstance();
}
此时User对象已经被创建完成(这只是创建对象的一种方式 其余还有 new 对象(),User.class等,此文档不做详细描述)
3.通过反射机制获取到User实例的方法 构造函数 变量等
按照步骤2的话 我们此时也可以user.getAge01();方式获取方法;
此刻采用反射机制去获取getAge01方法
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> clazz = Class.forName("com.example.User");
User user = (User) clazz.newInstance();
System.out.println("Class name="+clazz.getName());
Method getAge01 = clazz.getMethod("getAge01", String.class);
getAge01.invoke(user,"dd");
}
控制台打印:
Class name=com.example.User
getAge01dd年龄为12岁
与预期结果一致;
以相同的方式执行getAge02方法(该方法为private方法);
Class name=com.example.User
Exception in thread "main" java.lang.NoSuchMethodException: com.example.User.getAge02()
at java.lang.Class.getMethod(Class.java:1786)
at com.example.TestIOC.main(TestIOC.java:13)
出现错误信息 : NoSuchMethodException
这是因为该方法为private修饰不可被访问
只需修改代码为:
Class<?> clazz = Class.forName("com.example.User");
User user = (User) clazz.newInstance();
System.out.println("Class name="+clazz.getName());
Method getAge02 = clazz.getDeclaredMethod("getAge02");
getAge02.setAccessible(true);
getAge02.invoke(user);
打印日志为:
Class name=com.example.User
getAge02年龄为12岁
getDeclaredMethod与getMethod的区别
getMethod指代能获取当前类的公共方法及extends的方法
getDeclaredMethod指代能获取当前类除extends方法之外的方法包括 public private protected等
所以此处使用 getDeclareMethod获取私有方法
而使用setAccessible 设置为true的作用为让此私有方法可供外部调用
不设置的外会出现如下错误:
Class name=com.example.User
Exception in thread "main" java.lang.IllegalAccessException: Class com.example.TestIOC can not access a member of class com.example.User with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Method.invoke(Method.java:491)
at com.example.TestIOC.main(TestIOC.java:15)
这样我们就通过Java的反射机制调用了类的内部私有方法;
当然你也可以通过反射机制的API获取私有的变量 构造函数等,此处就不多做解释了,万变不离其宗;
贴常用API链接
注意:使用反射机制时也会破坏封装类的安全性,在实际项目中酌情使用
前人栽树,后人乘凉,快哉;