Step3 才是真正的功能实现,前面两步分别测试两个功能(扫描目录、给对象赋值),有助于理解Step3。
扫描功能在Step3中,写SptringContext类的功能时候会用到,这里热身。
Note:
package cn.edut.com.tarena;
import java.io.File;
import java.net.URLDecoder;
public class Test1 {
public static void main(String[] args) throws Exception {
// 获取bin目录的完整路径
String path = Test1.class.getResource("/").getPath();
path= URLDecoder.decode(path,"UTF-8");
System.out.println("path="+path);
// 扫描文件
File file = new File(path);
scan(file);//扫描目录,找到所有的class文件
}
private static void scan(File file) {
scan(file,0);
}
private static void scan(File file, int deph) {
//对文件夹列表
if(file.isDirectory()) {
showFile(file.getName() , deph);
File[] files = file.listFiles();
//路径不存在,文件夹没有权限进入,会得到null值
if (files == null) {
return ;
}
//对所有的子文件和子目录
for (File f : files) {
scan(f,deph+1);
}
}else if(file.isFile()) {
showFile(file.getName(), deph);
}else {
throw new RuntimeException() ;
}
}
private static void showFile(String name, int deph) {
for(int i=0 ; i<deph ; i++) {
System.out.print("\\-- ");
}
System.out.println(name);
}
}
SpringBoot中的配置文件application.yml
我们也模仿使用 :
新建项目: day16
右键点击项目–build path–add external …
application.yml
yaml - yet another markup language - 夜猫
不能使用tab制表符,都要使用空格
同一层次,必须对齐,至少两个空格2
冒号后面需要加空格
在src下新建文件 application.yml
spring:
datasource:
driver: com.mysql.jdbc.Driver
username: root
password: "123456"
url: jdbc:mysql://127.0.0.1:3306/jt?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
处理:
处理.yml也是使用jackson,但是要加插件snakeyaml-1.23
加载yml文件的工具类
使用 jackson 提供了 yaml 数据处理工具,来读取解析yml配置文件
加载后的数据结构:三层map
工具下载:https://download.csdn.net/download/LawssssCat/11996025
package cn.edut.com.tarena.spring;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import ognl.Ognl;
import ognl.OgnlException;
public class Configure {
//step1 : map/load()/get(String exp)
//step2 : TODO load()
//step3 : TODO get(String exp)
private static Map<String,Map> map ;
/**
* 用来加载配置,把yml配置数据解析,生成一个map集合
*/
@SuppressWarnings("unchecked")
public static void load() throws IOException {
String path = Configure.class.getResource("/application.yml").getPath();
path = URLDecoder.decode(path,"UTF-8");
//使用 jackson + yaml 插件,来解析处理yaml格式数据
ObjectMapper m = new ObjectMapper(new YAMLFactory());
//读取配置文件,把数据处理成一个map对象
map = m.readValue(new File(path), Map.class ) ;
}
/**
* "${spring.datasource.driver}" --- OGNL
* step1 : 处理${} replaceAll
* step2 : Ognl.getValue()
* @throws OgnlException
*/
public static String get(String exp) throws OgnlException {
//空格替换成空
exp = exp.replaceAll("\\s+", "") ;
//把$()去掉
exp = exp.substring(2, exp.length()-1) ;
//用ognal工具,使用实行表达式从map提取数据
String value = (String) Ognl.getValue(exp, map);
return value ;
}
public static void main(String[] args) throws Exception {
System.out.println("----load()-------");
load();
System.out.println(map.toString());
System.out.println("---get()-------");
//${spring.datasource.driver}
String testGet = get("$ { sp ring . datas ou rce.dri v er } ");
System.out.println(testGet);
}
}
自定义的@value注解:
package cn.edut.com.tarena.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface value {
String value() ;
}
定义一个要用value注解赋值的
UserDao类:
package cn.edut.com.tarena.spring;
public class UserDao {
@value("${spring.datasource.url}")
private String url ;
@value("${spring.datasource.username}")
private String username ;
@value("${spring.datasource.password}")
private String password ;
@value("${spring.datasource.driver}")
private String driver;
private void test() {
System.out.println("\n----自动填充的数据----------");
System.out.println("url="+url);
System.out.println("username="+username);
System.out.println("password="+password);
System.out.println("driver="+driver);
}
}
package cn.edut.com.tarena;
import java.lang.reflect.Field;
import cn.edut.com.tarena.spring.Configure;
import cn.edut.com.tarena.spring.UserDao;
import cn.edut.com.tarena.spring.Value;
public class Test2 {
public static void main(String[] args) throws Exception {
Configure.load();
//新建UserDao实例,并自动填充它的属性
UserDao userDao = new UserDao();
//获取所有的成员变量
Field[] fields = userDao.getClass().getDeclaredFields();
//遍历变量
for (Field field : fields) {
//变量上是哦否存在@Value注解
if(field.isAnnotationPresent(Value.class)) {
//获取@Value注解
Value annotation = field.getAnnotation(Value.class);
String exp = annotation.value();//从注解获取ognl表达式
//如果没有ognl(这里忽略)
//用value当ognl(这里忽略)
//用get方法解析ognl表达式,获得value
String value = Configure.get(exp) ;
//私有变量可访问
field.setAccessible(true);
//把输出的配置数据,保存到变量实例userDao
field.set(userDao, value);
}
}
userDao.test();
}
}
自动扫描、自动创建对象、自动赋值,本质上就实现下面的两种模式
IoC - Inverse of Control 控制权翻转
控制翻转,自己不控制对象的创建,而是权利翻转,交给工具来创建对象需要对象,从工具来取用
DI - Dependency Injection 依赖注入
对象需要的数据,使用的其他对象,进行自动装配
自动在类路径中扫描,找到所有添加了以下注解的类,并自动创建实例
SpringContext - Spring环境对象,上下文对象
包含一个map集合:
Key | Value |
---|---|
“day16.UserDao” | UserDao实例 |
“day16.UserService” | UserService实例 |
“day16.UserController” | UserController实例 |
/
|- day16
|- UserDao
|- UserService
|- UserControler
|- pojo
|- A
|- B
|- xxx
|- ...
|- day15
|- X
|- Y
UserDao上面准备好了,现在准备两个类的模型 (UserController类、UserServer类)
package cn.edut.com.tarena.spring;
public class UserController {
private UserService userService ;
public void test() {
System.out.println("\n--控制器对象--------------");
System.out.println("调用业务对象 - "+userService);
userService.test();
}
}
package cn.edut.com.tarena.spring;
public class UserService {
private UserDao userDao ;
public void test() {
System.out.println("\n--业务对象-----------------");
System.out.println("调用数据对象 - "+userDao);
userDao.test();
}
}
扫描实现:
package cn.edut.com.tarena.spring;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/*
* 自动在bin目录下,扫描所有的class文件,并创建实例,放入map集合
* [bin]
* |- [aa]
* |- A.class
* |- B.class
* |- [bb]
* |- C.class
* |- D.class
* |- [cc]
* |- E.class
* |- F.class
*
* 包名"aa.bb.cc"
*/
public class SpringContext {
private Map<String , Object> map = new HashMap<>();
/**
* 自动在bin目录下,扫描所有的class文件,并创建实例,放入map集合
*/
public void autoScan() throws Exception {
String path = SpringContext.class.getResource("/").getPath();
path = URLDecoder.decode(path,"UTF-8");
File file = new File(path+"/cn");
//扫描目录, pkg 用来处理包民
StringBuilder pkg = new StringBuilder();
scan(file , pkg);
}
private void scan(File dir, StringBuilder pkg) {
if(dir == null || pkg==null) {
throw new RuntimeException();
}
String name = dir.getName();
if(dir.isDirectory())
{
//dir是目录
File[] list = dir.listFiles();
if(list==null) {
return ;
}
pkg.append(name);
System.out.println(pkg);
for (File file : list) {
pkg.append(".");
scan(file, pkg);
pkg.delete(pkg.length()-1, pkg.length());
}
pkg.delete(pkg.length()-name.length(), pkg.length());
}else if(dir.isFile())
{
//dir 是文件
pkg.append(name) ;
String suffix = ".class" ;
if(pkg.toString().endsWith(suffix)) {
String pkgName = pkg.subSequence(0 , pkg.length()-suffix.length()).toString();
try {
Object newInstance = Class.forName(pkgName).newInstance();
map.put(pkgName, newInstance);
} catch (Exception e) {
System.out.println(pkgName + "无法创建实例");
}
}
System.out.println(pkg);
pkg.delete(pkg.length()-name.length(), pkg.length());
}
}
public static void main(String[] args) throws Exception {
SpringContext c = new SpringContext();
c.autoScan();
System.out.println("--创建的实例-----------");
Set<Entry<String, Object>> entrySet = c.map.entrySet();
for (Entry<String, Object> entry : entrySet) {
System.out.println(entry.getKey()+" - "+entry.getValue());
}
}
}
扫描结果:
cn
cn.edut
cn.edut.com
cn.edut.com.tarena
cn.edut.com.tarena.spring
cn.edut.com.tarena.spring.Configure.class
cn.edut.com.tarena.spring.SpringContext.class
cn.edut.com.tarena.spring.Test003.class
cn.edut.com.tarena.spring.UserController.class
cn.edut.com.tarena.spring.UserDao.class
cn.edut.com.tarena.spring.UserService.class
cn.edut.com.tarena.spring.Value无法创建实例
cn.edut.com.tarena.spring.Value.class
cn.edut.com.tarena.Test1.class
cn.edut.com.tarena.Test2.class
–创建的实例-----------
cn.edut.com.tarena.spring.UserService - cn.edut.com.tarena.spring.UserService@1d35f92f
cn.edut.com.tarena.Test2 - cn.edut.com.tarena.Test2@427a8ba4
cn.edut.com.tarena.spring.Test003 - cn.edut.com.tarena.spring.Test003@7b65de14
cn.edut.com.tarena.Test1 - cn.edut.com.tarena.Test1@5cd73256
cn.edut.com.tarena.spring.UserController - cn.edut.com.tarena.spring.UserController@3429dbb8
cn.edut.com.tarena.spring.Configure - cn.edut.com.tarena.spring.Configure@281827c9
cn.edut.com.tarena.spring.UserDao - cn.edut.com.tarena.spring.UserDao@49dc11af
cn.edut.com.tarena.spring.SpringContext - cn.edut.com.tarena.spring.SpringContext@f0d1e0b
问题1:为什么创建这三个注解?
答:有选择的创建对象,节省空间
问题2:为什么用三个注解?
答:只是方便阅读,其实功能是一样的
Component 组件
Service
Controller 控制器
@Component注解(三个注解名字外一样,直接复制)
package cn.edut.com.tarena.spring.anno;
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 Component {
}
@Controller 注解
package cn.edut.com.tarena.spring.anno;
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 Controller {
}
@Service 注解
package cn.edut.com.tarena.spring.anno;
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 Service {
}
更新后的SpringContext类
package cn.edut.com.tarena.spring;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import cn.edut.com.tarena.spring.anno.Component;
import cn.edut.com.tarena.spring.anno.Controller;
import cn.edut.com.tarena.spring.anno.Service;
import java.util.Set;
/*
* 自动在bin目录下,扫描所有的class文件,并创建实例,放入map集合
* [bin]
* |- [aa]
* |- A.class
* |- B.class
* |- [bb]
* |- C.class
* |- D.class
* |- [cc]
* |- E.class
* |- F.class
*
* 包名"aa.bb.cc"
*/
public class SpringContext {
private Map<String , Object> map = new HashMap<>();
/**
* 自动在bin目录下,扫描所有的class文件,并创建实例,放入map集合
*/
public void autoScan() throws Exception {
String path = SpringContext.class.getResource("/").getPath();
path = URLDecoder.decode(path,"UTF-8");
File file = new File(path+"/cn");
//扫描目录, pkg 用来处理包民
StringBuilder pkg = new StringBuilder();
scan(file , pkg);
}
private void scan(File dir, StringBuilder pkg) {
if(dir == null || pkg==null) {
throw new RuntimeException();
}
String name = dir.getName();
if(dir.isDirectory())
{
//dir是目录
File[] list = dir.listFiles();
if(list==null) {
return ;
}
pkg.append(name);
System.out.println(pkg);
for (File file : list) {
pkg.append(".");
scan(file, pkg);
pkg.delete(pkg.length()-1, pkg.length());
}
pkg.delete(pkg.length()-name.length(), pkg.length());
}else if(dir.isFile())
{
//dir 是文件
pkg.append(name) ;
String suffix = ".class" ;
if(pkg.toString().endsWith(suffix)) {
String pkgName = pkg.subSequence(0 , pkg.length()-suffix.length()).toString();
try {
Class<?> clazz = Class.forName(pkgName);
if(clazz.isAnnotationPresent(Component.class) ||
clazz.isAnnotationPresent(Controller.class) ||
clazz.isAnnotationPresent(Service.class)) {
Object newInstance = clazz.newInstance();
map.put(pkgName, newInstance);
}
} catch (Exception e) {
System.out.println(pkgName + "无法创建实例");
}
}
System.out.println(pkg);
pkg.delete(pkg.length()-name.length(), pkg.length());
}
}
public <T> T getObject(Class<T> c) {
String name = c.getName();
return (T) map.get(name);
}
public static void main(String[] args) throws Exception {
SpringContext c = new SpringContext();
c.autoScan();
System.out.println("--创建的实例-----------");
Set<Entry<String, Object>> set1 = c.map.entrySet();
for (Entry<String, Object> entry : set1) {
System.out.println(entry.getKey()+" - "+entry.getValue());
}
System.out.println("--自动填充数据-----------");
UserDao userDao = c.getObject(UserDao.class);
userDao.test();
UserService userService = c.getObject(UserService.class);
//userService.test();
}
}
整理了一下目录
控制台结果
cn
cn.edut
cn.edut.com
cn.edut.com.tarena
cn.edut.com.tarena.spring
cn.edut.com.tarena.spring.anno
cn.edut.com.tarena.spring.anno.Component.class
cn.edut.com.tarena.spring.anno.Controller.class
cn.edut.com.tarena.spring.anno.Service.class
cn.edut.com.tarena.spring.anno.Value.class
cn.edut.com.tarena.spring.Configure.class
cn.edut.com.tarena.spring.SpringContext.class
cn.edut.com.tarena.spring.Test003.class
cn.edut.com.tarena.spring.UserController.class
cn.edut.com.tarena.spring.UserDao.class
cn.edut.com.tarena.spring.UserService.class
cn.edut.com.tarena.Test1.class
cn.edut.com.tarena.Test2.class
--创建的实例-----------
cn.edut.com.tarena.spring.UserService - cn.edut.com.tarena.spring.UserService@3f9432e0
cn.edut.com.tarena.spring.UserController - cn.edut.com.tarena.spring.UserController@1a9830bc
cn.edut.com.tarena.spring.UserDao - cn.edut.com.tarena.spring.UserDao@7da79447
--自动填充数据-----------
----自动填充的数据----------
url=null
username=null
password=null
driver=null
自动装配 - autowired
现在实现依赖注入:
- DI - Dependency Injection 依赖注入
对象需要的数据,使用的其他对象,进行自动装配
先给需要注入数据的属性添加注解
给UserController、UserService类的属性添加 @AutoWired 注解,自动填充属性数据 - 自动装配 - 依赖注入
package cn.edut.com.tarena.spring.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
}
在UserController、UserService类中的修改:
autoWired() - 方法
/**
* 自动装配
*
* 分析:
* 现在map里面的数据:
* map
*
* key value
* ------------------------------------------------------------------
* cn.edut.com.tarena.spring.UserService UserDao实例
* cn.edut.com.tarena.spring.UserController UserService实例
* cn.edut.com.tarena.spring.UserDao UserController实例
* @throws Exception
*/
private void autoWired() throws Exception {
Collection<Object> values = map.values();
for (Object object : values) {
Class<? extends Object> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(AutoWired.class)) {
//如果是需要装配的
//注入对象
injectObject(object,field);
}else if(field.isAnnotationPresent(Value.class)) {
//如果是数据
//注入配置数据
injectValue(object, field);
}
}
}
}
private void injectObject(Object object, Field field) throws Exception {
Class<?> type = field.getType();
Object injectObject = this.getObject(type);
field.setAccessible(true);
field.set(object, injectObject);
}
private void injectValue(Object object, Field field) throws Exception {
//从配置文件获取要注入的数据
Value annotation = field.getAnnotation(Value.class); //获得变量上的@Value注解
String value = annotation.value();//获取ognl表达式
String v = Configure.get(value); //从配置文件中获取配置数据
//注入数据
field.setAccessible(true);//修改访问权限
field.set(object, v);//把配置数据v,保存到变量f
}
测试结果:
cn
cn.edut
cn.edut.com
cn.edut.com.tarena
cn.edut.com.tarena.spring
cn.edut.com.tarena.spring.anno
cn.edut.com.tarena.spring.anno.AutoWired.class
cn.edut.com.tarena.spring.anno.Component.class
cn.edut.com.tarena.spring.anno.Controller.class
cn.edut.com.tarena.spring.anno.Service.class
cn.edut.com.tarena.spring.anno.Value.class
cn.edut.com.tarena.spring.Configure.class
cn.edut.com.tarena.spring.SpringContext.class
cn.edut.com.tarena.spring.Test003.class
cn.edut.com.tarena.spring.UserController.class
cn.edut.com.tarena.spring.UserDao.class
cn.edut.com.tarena.spring.UserService.class
cn.edut.com.tarena.Test1.class
cn.edut.com.tarena.Test2.class
--创建的实例-----------
cn.edut.com.tarena.spring.UserService - cn.edut.com.tarena.spring.UserService@793e6657
cn.edut.com.tarena.spring.UserController - cn.edut.com.tarena.spring.UserController@6fb117f0
cn.edut.com.tarena.spring.UserDao - cn.edut.com.tarena.spring.UserDao@539ac6d9
--自动填充数据-----------
**********************************
----UserDao数据----------
url=jdbc:mysql://127.0.0.1:3306/jt?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username=root
password=123456
driver=com.mysql.jdbc.Driver
**********************************
--业务对象-----------------
调用数据对象 - cn.edut.com.tarena.spring.UserDao@539ac6d9
----UserDao数据----------
url=jdbc:mysql://127.0.0.1:3306/jt?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username=root
password=123456
driver=com.mysql.jdbc.Driver
**********************************
--控制器对象--------------
调用业务对象 - cn.edut.com.tarena.spring.UserService@793e6657
--业务对象-----------------
调用数据对象 - cn.edut.com.tarena.spring.UserDao@539ac6d9
----UserDao数据----------
url=jdbc:mysql://127.0.0.1:3306/jt?allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username=root
password=123456
driver=com.mysql.jdbc.Driver
**********************************
package cn.edut.com.tarena.spring;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import cn.edut.com.tarena.spring.anno.AutoWired;
import cn.edut.com.tarena.spring.anno.Component;
import cn.edut.com.tarena.spring.anno.Controller;
import cn.edut.com.tarena.spring.anno.Service;
import cn.edut.com.tarena.spring.anno.Value;
import ognl.Ognl;
import ognl.OgnlException;
import sun.security.krb5.Config;
import java.util.Set;
/*
* 自动在bin目录下,扫描所有的class文件,并创建实例,放入map集合
* [bin]
* |- [aa]
* |- A.class
* |- B.class
* |- [bb]
* |- C.class
* |- D.class
* |- [cc]
* |- E.class
* |- F.class
*
* 包名"aa.bb.cc"
*/
public class SpringContext {
private Map<String , Object> map = new HashMap<>();
/**
* 自动在bin目录下,扫描所有的class文件,并创建实例,放入map集合
*/
public void autoScan() throws Exception {
String path = SpringContext.class.getResource("/").getPath();
path = URLDecoder.decode(path,"UTF-8");
File file = new File(path+"/cn");
//扫描目录, pkg 用来处理包民
StringBuilder pkg = new StringBuilder();
scan(file , pkg);
autoWired();
}
/**
* 自动装配
*
* 分析:
* 现在map里面的数据:
* map
*
* key value
* ------------------------------------------------------------------
* cn.edut.com.tarena.spring.UserService UserDao实例
* cn.edut.com.tarena.spring.UserController UserService实例
* cn.edut.com.tarena.spring.UserDao UserController实例
* @throws Exception
*/
private void autoWired() throws Exception {
Collection<Object> values = map.values();
for (Object object : values) {
Class<? extends Object> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(AutoWired.class)) {
//如果是需要装配的
//注入对象
injectObject(object,field);
}else if(field.isAnnotationPresent(Value.class)) {
//如果是数据
//注入配置数据
injectValue(object, field);
}
}
}
}
private void injectObject(Object object, Field field) throws Exception {
Class<?> type = field.getType();
Object injectObject = this.getObject(type);
field.setAccessible(true);
field.set(object, injectObject);
}
private void injectValue(Object object, Field field) throws Exception {
//从配置文件获取要注入的数据
Value annotation = field.getAnnotation(Value.class); //获得变量上的@Value注解
String value = annotation.value();//获取ognl表达式
String v = Configure.get(value); //从配置文件中获取配置数据
//注入数据
field.setAccessible(true);//修改访问权限
field.set(object, v);//把配置数据v,保存到变量f
}
private void scan(File dir, StringBuilder pkg) {
if(dir == null || pkg==null) {
throw new RuntimeException();
}
String name = dir.getName();
if(dir.isDirectory())
{
//dir是目录
File[] list = dir.listFiles();
if(list==null) {
return ;
}
pkg.append(name);
System.out.println(pkg);
for (File file : list) {
pkg.append(".");
scan(file, pkg);
pkg.delete(pkg.length()-1, pkg.length());
}
pkg.delete(pkg.length()-name.length(), pkg.length());
}else if(dir.isFile())
{
//dir 是文件
pkg.append(name) ;
String suffix = ".class" ;
if(pkg.toString().endsWith(suffix)) {
String pkgName = pkg.subSequence(0 , pkg.length()-suffix.length()).toString();
try {
Class<?> clazz = Class.forName(pkgName);
if(clazz.isAnnotationPresent(Component.class) ||
clazz.isAnnotationPresent(Controller.class) ||
clazz.isAnnotationPresent(Service.class)) {
Object newInstance = clazz.newInstance();
map.put(pkgName, newInstance);
}
} catch (Exception e) {
System.out.println(pkgName + "无法创建实例");
}
}
System.out.println(pkg);
pkg.delete(pkg.length()-name.length(), pkg.length());
}
}
public <T> T getObject(Class<T> c) {
String name = c.getName();
return (T) map.get(name);
}
public static void main(String[] args) throws Exception {
//在自动扫描之前,先加载
Configure.load();
//自动扫描
SpringContext c = new SpringContext();
c.autoScan();
System.out.println("--创建的实例-----------");
Set<Entry<String, Object>> set1 = c.map.entrySet();
for (Entry<String, Object> entry : set1) {
System.out.println(entry.getKey()+" - "+entry.getValue());
}
System.out.println("--自动填充数据-----------");
System.out.println("**********************************");
UserDao userDao = c.getObject(UserDao.class);
userDao.test();
System.out.println("**********************************");
UserService userService = c.getObject(UserService.class);
userService.test();
System.out.println("**********************************");
UserController userController = c.getObject(UserController.class);
userController.test();
System.out.println("**********************************");
}
}
package cn.edut.com.tarena.spring;
import cn.edut.com.tarena.spring.anno.AutoWired;
import cn.edut.com.tarena.spring.anno.Controller;
@Controller
public class UserController {
//自动装配
//自动从SpringContext中,获取UserService实例,保存到这变量
@AutoWired
private UserService userService ;
public void test() {
System.out.println("\n--控制器对象--------------");
System.out.println("调用业务对象 - "+userService);
userService.test();
}
}
package cn.edut.com.tarena.spring;
import cn.edut.com.tarena.spring.anno.AutoWired;
import cn.edut.com.tarena.spring.anno.Service;
@Service
public class UserService {
@AutoWired
private UserDao userDao ;
public void test() {
System.out.println("\n--业务对象-----------------");
System.out.println("调用数据对象 - "+userDao);
userDao.test();
}
}
package cn.edut.com.tarena.spring;
import cn.edut.com.tarena.spring.anno.Component;
import cn.edut.com.tarena.spring.anno.Value;
@Component
public class UserDao {
@Value("${spring.datasource.url}")
private String url ;
@Value("${spring.datasource.username}")
private String username ;
@Value("${spring.datasource.password}")
private String password ;
@Value("${spring.datasource.driver}")
private String driver;
public void test() {
System.out.println("\n----UserDao数据----------");
System.out.println("url="+url);
System.out.println("username="+username);
System.out.println("password="+password);
System.out.println("driver="+driver);
}
}
package cn.edut.com.tarena.spring;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import ognl.Ognl;
import ognl.OgnlException;
public class Configure {
//step1 : map/load()/get(String exp)
//step2 : TODO load()
//step3 : TODO get(String exp)
private static Map<String,Map> map ;
/**
* 用来加载配置,把yml配置数据解析,生成一个map集合
*/
@SuppressWarnings("unchecked")
public static void load() throws IOException {
String path = Configure.class.getResource("/application.yml").getPath();
path = URLDecoder.decode(path,"UTF-8");
//使用 jackson + yaml 插件,来解析处理yaml格式数据
ObjectMapper m = new ObjectMapper(new YAMLFactory());
//读取配置文件,把数据处理成一个map对象
map = m.readValue(new File(path), Map.class ) ;
}
/**
* "${spring.datasource.driver}" --- OGNL
* step1 : 处理${} replaceAll
* step2 : Ognl.getValue()
* @throws OgnlException
*/
public static String get(String exp) throws Exception {
//空格替换成空
exp = exp.replaceAll("\\s+", "") ;
//把$()去掉
exp = exp.substring(2, exp.length()-1) ;
//用ognal工具,使用实行表达式从map提取数据
String value = (String) Ognl.getValue(exp, map);
return value ;
}
public static void main(String[] args) throws Exception {
System.out.println("----load()-------");
load();
System.out.println(map.toString());
System.out.println("---get()-------");
//${spring.datasource.driver}
String testGet = get("$ { sp ring . datas ou rce.dri v er } ");
System.out.println(testGet);
}
}
package cn.edut.com.tarena.spring.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
}
package cn.edut.com.tarena.spring.anno;
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 Component {
}
package cn.edut.com.tarena.spring.anno;
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 Controller {
}
package cn.edut.com.tarena.spring.anno;
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 Service {
}
package cn.edut.com.tarena.spring.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Value {
String value() ;
}