学习目标
在第五章学习了Spring框架的一些基础概念和操作,同学们已经对Spring框架有了基本的了解。(如果没有了解可以去我主页看看 第一至五章 的内容来学习)本章将对第五章中的内容进行扩展学习,进一步感受Spring框架功能强大和使用方便的优势。
6.1 增强类型扩展
在Java中,类型扩展通常指的是在现有类型的基础上增加新的功能或属性,但这并不是Java直接支持的一种特性,因为Java是一种静态类型语言,其类型系统相对固定。不过,我们可以通过几种不同的方式来实现类似“增强类型”的效果:
1. 继承(Inheritance)
这是最直接的方式,通过定义一个子类继承父类,你可以在子类中增加新的方法或属性,从而“扩展”父类的功能。但是,这种方式仅限于类之间的扩展,不适用于接口或已存在的第三方库中的类(除非这些类被设计为可以被扩展)。
class Animal {
void eat() {
System.out.println("This animal eats food.");
}
}
class Dog extends Animal {
void bark() {
System.out.println("Woof!");
}
}
2. 组合(Composition)
如果你不能或不想通过继承来扩展类型,可以使用组合。这意味着你可以在一个类中持有另一个类的实例,并通过这个实例来访问其方法。这样,你可以在你的类中添加新的方法或属性,并且可以通过组合进来的实例来使用其方法。
class Engine {
void start() {
System.out.println("Engine started.");
}
}
class Car {
private Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void startEngine() {
engine.start();
}
void openDoor() {
System.out.println("Door opened.");
}
}
3. 装饰者模式(Decorator Pattern)
装饰者模式允许你动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式相比生成子类更为灵活。这种模式创建了一个包装对象,也就是装饰器,来包裹真实的对象。
interface Component {
void operation();
}
class ConcreteComponent implements Component {
public void operation() {
System.out.println("ConcreteComponent's operation");
}
}
class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
public void operation() {
component.operation();
}
}
class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
public void operation() {
super.operation();
addedFunctionality();
}
void addedFunctionality() {
System.out.println("New Functionality Added by ConcreteDecoratorA");
}
}
4. 使用Java 8及以上版本的默认方法和静态方法
如果你正在扩展接口,并且希望为接口添加新方法而不破坏实现了该接口的旧类,可以使用Java 8引入的默认方法(default methods)和静态方法(static methods)。
interface MyInterface {
default void defaultMethod() {
System.out.println("This is a default method.");
}
static void staticMethod() {
System.out.println("This is a static method.");
}
}
注意
虽然默认方法和静态方法可以让你在接口中“添加”新方法,但它们并不真正改变已经存在的类型的“行为”,只是为实现了该接口的类提供了额外的功能。
6.1.1 异常抛出增强
异常抛出增强是指当目标对象方法抛出异常时进行织入操作的一种增强方式。通常,异常抛出增强用来为项目提供统一的异常处理功能,具有可灵活插拨的特点。
使用异常抛出增强时,需要在配置文件中使用<aop:after-throwing>
标签进行配置,语法如下。
语法:
<aop:config>
<aop:aspect ref="增强方法所在的Bean">
<aop:after-throwing method="增强处理方法"
pointcut-ref="切入点id" throwing="e"/>
</aop:aspect>
</aop:config>
上述语法中,<aop:after-throwing>
标签表示增强处理类型为异常抛出增强。
在Java中,异常抛出是处理运行时错误的一种重要机制。通过抛出异常,你可以让方法在遇到无法处理或不应处理的错误时,通知调用者。这种机制增强了代码的健壮性和可维护性。下面是如何在Java代码中通过抛出异常来增强其健壮性的一些示例:
1. 自定义异常
首先,你可以通过继承Exception类(对于可检查的异常)或RuntimeException类(对于运行时异常)来创建自定义异常。这有助于你更清晰地表达错误的性质,并提供更具体的错误信息。
public class MyCustomException extends Exception {
public MyCustomException(String message) {
super(message);
}
// 可以添加其他构造器或方法
}
2. 在方法中抛出异常
当方法无法继续执行其任务时,可以抛出异常。这可以是自定义异常,也可以是Java标准库中的异常。
public void doSomething(int number) throws MyCustomException {
if (number < 0) {
throw new MyCustomException("Number cannot be negative");
}
// 其他逻辑...
}
3. 捕获并处理异常
调用可能抛出异常的方法时,你应该捕获这些异常并适当处理它们。这可以通过try-catch块来完成。
try {
doSomething(-1);
} catch (MyCustomException e) {
System.err.println("Caught an exception: " + e.getMessage());
// 处理异常,例如记录日志、回滚事务、显示错误消息等
}
4. 使用throws声明
如果方法不处理某个异常,但认为调用者应该处理它,那么可以在方法签名中使用throws关键字来声明该方法可能抛出的异常。
public void anotherMethod() throws IOException, MyCustomException {
// 方法体...
// 可能抛出IOException或MyCustomException
}
5. 异常链
在处理异常时,有时需要将一个异常包装在另一个异常中,并抛出新的异常。这可以通过在构造器中传递原始异常作为参数来实现,从而保持异常的上下文信息。
try {
// 可能抛出IOException的代码
} catch (IOException e) {
throw new MyCustomException("Failed to perform operation", e);
}
6. 合理使用检查型异常和运行时异常
- 检查型异常(如IOException)应该用于那些合理的、可恢复的或需要调用者特别关注的异常情况。
- 运行时异常(如NullPointerException、IllegalArgumentException)通常用于指示编程错误,如空指针引用、无效的参数等,这些错误通常是由程序员的失误引起的,而不是由外部因素引起的。
6.1.2 最终增强
最终增强是指无论目标对象的方法正常运行还是抛出异常,该增强处理都会执行的一种增强方式。其与Java中finally代码块的作用相似,通常用于释放资源等操作,具有可灵活插拨的特点。
使用最终增强,需要在配置文件中使用aop:after标签进行配置,语法如下。
语法:
<aop:config>
<aop:aspect ref="增强方法所在的Bean">
<aop:after method="增强处理方法" pointcut-ref="切入点id">
</aop:aspect>
</aop:config>
6.1.3 环绕增强
环绕增强是指在目标对象方法前后都可以进行织人的一种增强处理方式。在环绕增强处理中,可以获取修改目标方法的参数、返回值,可以对它进行异常处理,甚至可以决定目标方法是否被执行。
使用环绕增强,需要在配置文件中使用<aop:around>
标签进行配置,语法如下。
语法:
<aop:config>
<aop:aspect ref="增强方法所在的 Bean">
<aop:around method="增强处理方法" pointcut-ref="切入点id"/>
</aop:aspect>
</aop:config>
6.2 依赖注入方式扩展
在第5章我们学习了Spring IOC通过setter方法实现对属性的赋值功能,这种方式被称为设值注入。除此之外,Spring框架还提供了多种属性注入方式,下面逐一进行学习。
6.2.1 构造注入
构造注入的指Spring框架通过构造方法为属性赋值的一种注入方式。构造注入可以在对象初始化时为属性赋值,具有良好的时效性。
使用构造注入,需要在配置文件中使用<constructor-arg>
标签进行配置,语法如下。
语法:
<bean id="唯一标识" class="类的全路径">
<constructor-arg name="参数名称" ref="依赖对象"/>
</bean>