javaday16
1 回顾
l 基础API
n API - Application Programming Interface
应用编程接口,一切可以调用的东西
n Object
u toString() 默认格式"类型@地址"
u equals(Object) 比较是否相等,默认==比地址
u hashCode() 获得一个对象的哈希值
u wait()
u notify()
u notifyAll()
n String
u 封装 char[] 数组
u 常量池
u 不可变
u 加号连接效率低
String s1 = "aaa"
String s2 = "bbb"
String s3 = "ccc"
String s4 = s1+s2+s3
加号连接过程:
sb = new StringBuilder("aa");
sb.append("bb");
s = sb.toString();
String s4 = "aaa"+"bbb"+"ccc"
编译优化: String s4 = "aaabbbccc"
n StringBuilder/StringBuffer
u 用来代替字符串,做高效率字符串连接运算
u append()
u 内部char[]数组默认初始容量 16
u 翻倍增长 +2
n 正则表达式
u 百度"正则表达式大全", "用户名正则", "密码正则", "日期正则"
u 字符串的正则匹配运算方法:
s.matches(正则)
u 拆分: s.split(";")
u 替换: s.replaceAll(正则, 子串)
n Integer
u int的包装类
u 创建实例:
l new Integer(6)
l Integer.valueOf(6)
Integer类内部,存在一个Integer[]数组,其中缓存了256个Integer实例,封装的数字范围:-128到127
范围内的值,访问缓存对象
范围外的值,新建实例
n Date/SimpleDateFormat
l 集合
n ArrayList
u 数组
u 访问任意位置效率高
u 增删数据,效率可能降低
u 默认初始容量10
n LinkedList
u 双向链表
u 两端效率高
n HashMap
u 哈希表,散列表
u 键:
l 不重复
l 无序
u 哈希运算过程:
l key.hashCode()用哈希值计算下标i
l 键值对封装成Entry对象,放入i位置
2 第十六天:高级:手写JUnit+手写@Value+手写DI
l 今天没有新的知识点
l 难度非常高的练习
l 今天的练习不影响后面学习
2.1 配置信息注入到对象中
新建项目: 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 提供了 yaml 数据处理工具,来读取解析yml配置文件
加载后的数据结构:三层map
package day16;
import java.io.File;
import java.net.URLDecoder;
import java.util.HashMap;
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 {
private static Map<String, String> cfg = new HashMap<String, String>();
public static void load() throws Exception {
String path = Configure.class.getResource("/application.yml").getPath();
path = URLDecoder.decode(path, "UTF-8");
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
cfg = mapper.readValue(new File(path), Map.class);
}
public static String get(String expr) {
expr = expr.trim();
expr = expr.substring(2, expr.length()-1);
String r;
try {
r = (String) Ognl.getValue(expr, cfg);
return r;
} catch (OgnlException e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) throws Exception {
Configure.load();
System.out.println(cfg);
String driver = get("${spring.datasource.driver}");
String username = get("${spring.datasource.username}");
String password = get("${spring.datasource.password}");
String url = get("${spring.datasource.url}");
System.out.println(driver);
System.out.println(username);
System.out.println(password);
System.out.println(url);
}
}
Component注解
package day16;
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 {
}
Value注解
package day16;
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 name() default "";
String value() default "";
}
UserDao
l 有Component注解才创建对象,没有注解不创建对象
l Value注解把配置文件中的配置数据赋给变量
package day16;
@Component
public class UserDao {
@Value("${spring.datasource.driver}")
private String driver;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.url}")
private String url;
public void test() {
System.out.println("\n---UserDao中注入的JDBC连接信息--------------------");
System.out.println(driver);
System.out.println(username);
System.out.println(password);
System.out.println(url);
}
}
用下面的测试代码测试我们要实现的功能
package day16;
import java.lang.reflect.Field;
public class TestValue {
public static void main(String[] args) throws Exception {
Configure.load();
String className = "day16.UserDao";
Class<?> c = Class.forName(className);
if(c.isAnnotationPresent(Component.class)) {
Object obj = c.newInstance();
Field[] a = c.getDeclaredFields();
for (Field f : a) {
if (f.isAnnotationPresent(Value.class)) {
Value v = f.getAnnotation(Value.class);
String name = v.name();
if (name==null || name.equals("")) {
name = v.value();
}
String r = Configure.get(name);
f.setAccessible(true);
f.set(obj, r);
}
}
///////////////////////
UserDao dao = (UserDao) obj;
dao.test();
}
}
}
2.2 自动扫描并创建对象
l IoC - Inverse of Control
控制翻转,自己不控制对象的创建,而是权利翻转,交给工具来创建对象
需要对象,从工具来取用
l DI - Dependency Injection
依赖注入
对象需要的数据,使用的其他对象,进行自动装配
自动在类路径中扫描,找到所有添加了以下注解的类,并自动创建实例
l Component
l Service
l Controller
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
在对象种,对添加了@Autowired注解的变量进行自动注入
Service注解
package day16;
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 {
}
Controller注解
package day16;
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 {
}
Autowired注解
package day16;
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 {
}
UserService
package day16;
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void test() {
System.out.println("\n----UserService中注入的dao对象------------------------");
System.out.println(userDao);
userDao.test();
}
}
UserController
package day16;
@Controller
public class UserController {
@Autowired
private UserService userService;
public void test() {
System.out.println("\n----UserController中注入的service对象------------------------");
System.out.println(userService);
userService.test();
}
}
SpringContext
先完成第一步,扫描类路径下的类,并自动创建实例
package day16;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class SpringContext {
private static Map<String, Object> ctx = new HashMap<String, Object>();
public static void autoScan() throws Exception {
String path = SpringContext.class.getResource("/").getPath();
File dir = new File(path);
scan(dir, new StringBuilder());
}
private static void scan(File dir, StringBuilder pkg) throws Exception {
File[] files = dir.listFiles();
if(files == null) return;
for (File f : files) {
String name = f.getName();
if (f.isFile()) {
if (name.endsWith(".class")) {
handle(pkg.toString()+"."+f.getName().substring(0, name.length()-6));
}
} else {
if (pkg.length()!=0) {
pkg.append(".");
}
pkg.append(name);
scan(f, pkg);
pkg.delete(pkg.length()-name.length(), pkg.length());
}
}
}
private static void handle(String className) throws Exception {
System.out.println(className);
Class<?> c = Class.forName(className);
if (c.isAnnotationPresent(Component.class) ||
c.isAnnotationPresent(Service.class) ||
c.isAnnotationPresent(Controller.class)) {
Object obj = c.newInstance();
ctx.put(className, obj);
}
}
public static void main(String[] args) throws Exception {
autoScan();
System.out.println(ctx);
}
}
SpringContext
完成第二步,对象中的变量自动注入,完成对象的自动装配
package day16;
import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class SpringContext {
private static Map<String, Object> ctx = new HashMap<String, Object>();
static {
try {
Configure.load();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void autoScan() throws Exception {
String path = SpringContext.class.getResource("/").getPath();
File dir = new File(path);
scan(dir, new StringBuilder());
autowire();
}
private static void autowire() throws Exception {
for (Object obj : ctx.values()) {
Class<? extends Object> c = obj.getClass();
Field[] fields = c.getDeclaredFields();
for (Field f : fields) {
if (f.isAnnotationPresent(Value.class)) {
injectValue(obj, f);
}
if (f.isAnnotationPresent(Autowired.class)) {
injectObject(obj, f);
}
}
}
}
private static void injectValue(Object obj, Field f) throws Exception {
Value v = f.getAnnotation(Value.class);
String name = v.name();
if (name==null || name.equals("")) {
name = v.value();
}
String r = Configure.get(name);
f.setAccessible(true);
f.set(obj, r);
}
private static void injectObject(Object obj, Field f) throws Exception {
f.setAccessible(true);
String name = f.getType().getName();
Object obj2 = ctx.get(name);
f.set(obj, obj2);
}
private static void scan(File dir, StringBuilder pkg) throws Exception {
File[] files = dir.listFiles();
if(files == null) return;
for (File f : files) {
String name = f.getName();
if (f.isFile()) {
if (name.endsWith(".class")) {
handle(pkg.toString()+"."+f.getName().substring(0, name.length()-6));
}
} else {
if (pkg.length()!=0) {
pkg.append(".");
}
pkg.append(name);
scan(f, pkg);
pkg.delete(pkg.length()-name.length(), pkg.length());
}
}
}
private static void handle(String className) throws Exception {
System.out.println(className);
Class<?> c = Class.forName(className);
if (c.isAnnotationPresent(Component.class) ||
c.isAnnotationPresent(Service.class) ||
c.isAnnotationPresent(Controller.class)) {
Object obj = c.newInstance();
ctx.put(className, obj);
}
}
public static <V> V getObject(Class<V> c) {
return (V) ctx.get(c.getName());
}
public static void main(String[] args) throws Exception {
autoScan();
System.out.println(ctx);
UserController c = getObject(UserController.class);
c.test();
}
}