1.获取类路径的方式
package com.ydlclass.reflect;
import java.net.URL;
public class Bootstrap {
public static void main(String[] args) {
//获取ClassPath,继而可以拿到这个类路径下的所有文件
URL resource = Thread.currentThread().getContextClassLoader().getResource("com/ydlclass/tree");
//获取的是上下文类加载器;
System.out.println(resource.getPath());//返回的方式是unix的表示方式
//对于classLoader可以加载clas文件,也可以加载其他的文件;比如创建一个a.txt文件放在类路径下面,那么可以直接的找到这个文件;
//但是如果手动的将此文件移动至其他文件下,那么就无法直接找到,需要补上上面的内容
}
}
2.例如Dog,被Singleton所修饰,
package com.ydlclass.reflect;
import com.ydlclass.reflect.homeworks.annotation.Singleton;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Singleton
public class Dog {
private String name;
public int age;
public Dog() {
}
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public Dog(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void eat(){
eat(null);
}
public void eat(String foodName){
System.out.println(this.getName() + "正在吃:" + foodName);
}
}
3.使用FileUtils工具类将制定的文件下的路径名称变为全限定名称的一个数组
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FileUtils {
private static List<String> PATH = new ArrayList<>();
public static List<String> listAllClassName(File file){
File[] files = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isDirectory() || name.contains(".class");
}
});
if (files == null || files.length == 0){
return null;
}
for (File file1 : files) {
if (file1.isDirectory()){
listAllClassName(file1);
} else{
PATH.add(file1.getAbsolutePath());
}
}
return PATH.stream().map(new Function<String, String>() {
@Override
public String apply(String s) {
//获取之前不需要的,需要替换的文件名称
String unablePath = file.getAbsolutePath();
return s.replace(unablePath + "\\", "").
replace(".class", "").
replace("\\",".");
//如果使用replaceAll,其中需要传入一个正则表达式,替换一个"\"需要使用四个”\“
}
}).collect(Collectors.toList());
}
}
4.注解
package com.ydlclass.reflect.homeworks.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Singleton {
}
5.注解的处理器handler,SingletonHandler
package com.ydlclass.reflect.homeworks.handler;
import com.ydlclass.reflect.homeworks.annotation.Singleton;
import com.ydlclass.reflect.homeworks.context.ApplicationContext;
import java.util.List;
public class SingletonHandler {
public static void handle(List<String> classNames){
for (String className : classNames) {
Class<?> aClass = null;
try {
aClass = Class.forName(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取注解,
Singleton annotation = aClass.getAnnotation(Singleton.class);
//如果这个类是由@Singleton注解修饰的,就创建一个对象放在内存当中
if (annotation != null){
Object instance = null;
try {
instance = aClass.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
ApplicationContext.addSingleton(aClass,instance);
}
}
}
}
6.使用应用的上下文环境处理
package com.ydlclass.reflect.homeworks.context;
import com.ydlclass.reflect.Dog;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ApplicationContext {
//维护一个上下文环境,环境中存放着需要的环境
private final static Map<Class<?>,Object> CONTEXT = new ConcurrentHashMap<>(8);
public static void addSingleton(Class<?> clazz, Object entity){
ApplicationContext.CONTEXT.put(clazz,entity);
}
//把实例对象,从容器中取出来
public static <T> T getSingleton(Class<T> clazz){
return (T)ApplicationContext.CONTEXT.get(clazz);//类型转换
}
}
7.主要的调用
package com.ydlclass.reflect.homeworks;
import com.ydlclass.reflect.Dog;
import com.ydlclass.reflect.homeworks.annotation.Singleton;
import com.ydlclass.reflect.homeworks.context.ApplicationContext;
import com.ydlclass.reflect.homeworks.handler.SingletonHandler;
import com.ydlclass.reflect.homeworks.utils.FileUtils;
import java.io.File;
import java.io.FilenameFilter;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Bootstrap {
//使用静态代码块实现类刚被加载时就创建对象
static {
//获取ClassPath,继而可以拿到这个类路径下的所有文件
final URL resource = Thread.currentThread().getContextClassLoader().getResource("");
File file = new File(resource.getFile());
//封装的方法完成路径名称转变为全限定名称
List<String> classNames = FileUtils.listAllClassName(file);
//注解解析器处理对应的注解
SingletonHandler.handle(classNames);
}
public static void main(String[] args) {
//获取一个被Singleton修饰的类的对象
Dog dog = ApplicationContext.getSingleton(Dog.class);
System.out.println(dog.getName());
}
}
8.这样做的好处是:
上述就是spring框架的核心类似,程序一起动类一被加载,程序就保存了Application上下文,从上下文中获取实例对象(工程中有些就没有状态,比如有的类只有成员方法,没有具体的属性;那么这种的类适合使用ApplicationContext的方式获取实例对象);
规定了所有的人使用这个对象时就需要从这里去取得,而不是自己new;避免内存浪费
牺牲启动时间,但是节省了运行时的时间;
以后可以使用类似的方式,可以在创建的对象前加上注释,配合解析器就能完成默认值的赋值;
注解本身不能做太多的工作,但是可以配合反射,指定被某些注解注释的类创建对象等其他的操作;
这种方式指定了以后使用这个类是从容器中间获取,而不是自己去new;