服务端开发
Week1 概述
反射
Java通过反射来完成类的解耦
// 获取类的Class对象(反射的入口)
Class<?> personClass = Class.forName("com.example.Person"); // 完整类名
Person person = (Person) constructor.newInstance(); // 创建对象实例
问题:在运行时,对一个JAVA类,能否知道属性和方法;能否调用它的任意方法?答案是可以的,JAVA提供一种反射机制可以实现。
什么是JAVA的反射机制?
Java反射是Java被视为动态(或准动态)语言的关键性质。这个机制允许程序在运行时透过Reflection APIs 取得任何一个已知名称的class的内部信息,包括其modifiers (诸如public,static等)、superclass (例收如Object)、实现之interfaces(例如Cloneable),也包括fields和methods 的所有信息,并可于运行时改变fields 内容或唤起methods。
Java 反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java 可以加载一个运行时才得知名称的class,获得其完整结构。
public class ConstructorReflectionExample {
public static void main(String[] args) {
try {
Class<Student> studentClass = Student.class;
System.out.println("=== 所有构造方法 ===");
Constructor<?>[] constructors = studentClass.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("\n=== 使用不同构造方法创建实例 ===");
// 使用无参构造方法
Constructor<Student> constructor1 = studentClass.getConstructor();
Student student1 = constructor1.newInstance();
// 使用单参构造方法
Constructor<Student> constructor2 = studentClass.getConstructor(String.class);
Student student2 = constructor2.newInstance("张三");
// 使用双参构造方法
Constructor<Student> constructor3 = studentClass.getConstructor(String.class, int.class);
Student student3 = constructor3.newInstance("李四", 90);
} catch (Exception e) {
e.printStackTrace();
}
}
}
什么是注入?
注入(Dependency Injection, DI),中文常译为 “依赖注入”。它是 Spring 框架实现 “控制反转(Inversion of Control, IoC)” 这个核心思想的具体技术手段。
为了理解它,我们先拆解两个概念:
a) 依赖(Dependency)
一个对象(A)的正常工作,需要依赖于另一个对象(B),那么 B 就是 A 的依赖。
- 例如:一个
UserService对象需要调用UserDao对象的方法来操作数据库。那么UserDao就是UserService的依赖。
public class UserService {
// UserService 依赖于 UserDao
private UserDao userDao;
public void doSomething() {
userDao.queryUser(); // 没有UserDao,这个方法就无法工作
}
}
b) 传统的依赖处理方式(自己控制)
在传统编码中,UserService会自己负责创建(new)出它的依赖 UserDao。
public class UserService {
private UserDao userDao;
// 传统方式:自己在内部创建依赖
public UserService() {
this.userDao = new UserDao(); // 控制权在 UserService 自己手里
}
}
这种方式的问题在于耦合度太高。如果想把 UserDao换成 MockUserDao(用于测试)或者 AdvancedUserDao,就必须修改 UserService的源代码。
c) 注入的方式(别人给你,控制反转)
“注入”就是指:对象的依赖不是由对象自己创建,而是由一个外部的“容器”(比如 Spring)创建好,然后“注入”或“设置”到对象里面。
public class UserService {
private UserDao userDao;
// 注入方式:通过构造函数“被给予”依赖
public UserService(UserDao userDao) { // 容器会调用这个构造方法,并把创建好的UserDao传进来
this.userDao = userDao; // 依赖被从外部“注入”了
}
// 或者通过Setter方法“被给予”依赖
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
这时,UserService自己不再控制 UserDao的创建,而是被动接收。控制权从类内部反转到了外部容器,这就是 “控制反转”。而容器将依赖设置进去的这个动作,就是 “依赖注入”。
总结:注入就是由 Spring 容器把你需要的东西(依赖)主动送给你,而不是你自己去拿。 这样做极大地降低了代码的耦合度,提高了灵活性和可测试性。
Spring 是基于配置的框架
这个说法源于 Spring 实现“控制反转”的方式。既然对象的创建和组装不再由程序内部 new关键字来控制,那就必须有一种方式告诉 Spring 容器:
- 要创建哪些对象? (Bean)
- 这些对象之间的依赖关系是怎样的? (哪个 Bean 需要注入到哪个 Bean)
这种“告诉”的方式,就是 “配置”。Spring 的核心就是一个根据你的配置来组装程序的巨大工厂。
Spring 提供了多种配置方式,适应了不同时代的开发风格:
基于 XML 配置(早期经典方式):在
.xml文件里明确地声明 Bean 和依赖关系。<!-- 告诉Spring:请创建一个叫userDao的Bean,它是com.example.UserDao这个类的实例 --> <bean id="userDao" class="com.example.UserDao"/> <!-- 告诉Spring:请创建一个叫userService的Bean,并在构造时把上面的userDao传给它 --> <bean id="userService" class="com.example.UserService"> <constructor-arg ref="userDao"/> <!-- 配置依赖关系 --> </bean>基于注解配置(现在的主流方式):通过在代码中添加注解(Annotation)来隐式地配置。Spring 会扫描这些注解来理解你的意图。
@Component,@Service,@Repository,@Controller: 告诉 Spring,“请把我标记的这个类变成一个 Bean”@Autowired: 告诉 Spring,“请在这里自动注入一个合适的依赖”。
@Service // 配置:这是一个Bean,名叫userService public class UserService { @Autowired // 配置:请自动注入一个UserDao类型的Bean到这里 private UserDao userDao; }基于 Java 的配置(现代、灵活的方式):在一个专门的 Java 类中使用
@Configuration和@Bean注解来显式地配置,功能强大且类型安全。@Configuration public class AppConfig { @Bean // 告诉Spring:这个方法会返回一个UserDao对象,请将它管理为一个Bean public UserDao userDao() { return new UserDao(); } @Bean public UserService userService() { // 配置:通过调用方法,将userDao()返回的Bean注入到UserService的构造函数中 return new UserService(userDao()); } }
Servlet
Servlet 是一个用 Java 编写的程序,它运行在Web服务器或应用服务器内部,用于接收、处理和响应来自客户端(通常是Web浏览器)的请求,并动态生成Web内容。
部署
个人部署:内网穿透
企业级的部署:微服务架构
Week2 依赖注入
Spring的两个核心技术
DI(Dependency Injection)
保留抽象接口,让组件(Component)依赖于抽象接口,当组件要与其他实际的对象发生依赖关系时,由抽象接口来注入依赖的实际对象
AOP(Aspect Oriented Programming)
通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率




