容器
java容器又可以称为Java Collection Framework(JCF)。里面除了存储对象的容器之外,还提供了一套用于处理和操作容器里面的对象的一套工具类
注解
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
- @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(或者说 元注解)是:
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
从 Java 7 开始,额外添加了 3 个注解:
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
注解开发定义bean
步骤一 :Dao上添加注解
注意 :@Component 注解不可以添加在接口上,因为接口是无法创建对象的
//相当于给bean起了一个id,注解在哪个类上,class就是该类的类全名
@Component("bookDao")
public class BookServiceImpl implements BookService {
public void save() {
System.out.println("Book Service save..");
}
}
步骤二 : 配置 Spring 的注解包扫描
为了让 Spring 框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com"/>
</beans>
注解开发Bean作用范围和生命周期管理
Bean的作用范围
在注解开发Bean 的配置环境下,默认bean为单例模式
//默认为单例模式,所以 两个对象属于同一对象
public class Test {
public static void main(String[] args) {
加载配置类初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
BookDaoImpl bookDao1 = ctx.getBean(BookDaoImpl.class);
BookDaoImpl bookDao2 = ctx.getBean(BookDaoImpl.class);
System.out.println(bookDao1);
System.out.println(bookDao2);
}
}
要想将BookDaoImpl变成非单例,只需要在其类上添加@scope注解(singleton/property)
Bean的生命周期
(1) 在 BookDaoImpl 中添加两个方法, init 和 destroy , 方法名可以任意
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save(){
System.out.println("book Dao save..");
}
public void init(){
System.out.println("init..");
}
public void destory(){
System.out.println("destory..");
}
}
(2) 如何对方法进行标识,哪个是初始化方法,哪个是销毁方法 ?
只需要在对应的方法上添加 @PostConstruct 和 @PreDestroy 注解即可。
@Component("bookDao")
public class BookDaoImpl implements BookDao {
public void save(){
System.out.println("book Dao save..");
}
@PostConstruct 在构造方法之后执行,替换 init-method
public void init(){
System.out.println("init..");
}
@PreDestroy //在销毁方法之前执行,替换 destroy-method
public void destory(){
System.out.println("destory..");
}
}
(3) 要想看到两个方法执行,同样与传统开发方式一样,destory需要在容器关闭时才会执行,所以我们同样需要修改类
AnnotationConfigApplicationContext ctx = new
AnnotationConfigApplicationContext(SpringConfig.class);
注解开发依赖注入
注解实现按照类型注入
在 BookServiceImpl 类的 bookDao 属性上添加 @Autowired 注解
@Service
public class BookServiceImpl implements BookService {
//注解开发实现自动装配
@Autowired
private BookDao bookDao;
public void save() {
bookDao.save();
System.out.println("Book Service save..");
}
}
注意
(1)@Autowired 可以写在属性上,也可也写在 setter 方法上,最简单的处理方式是 写在属性上并将setter方法删除掉
- 自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值
- 普通反射只能获取public修饰的内容
- 暴力反射除了获取public修饰的内容还可以获取private修改的内容
- 所以此处无需提供setter方法
(2)@Autowored按照类型注入,那么BookDao接口如果有多个实现类,那么再按照类型搜索就会报错。故一个接口若有多个实现类,就需要使用按照名称注入
注解实现按照名称注入
当根据类型在容器中找到多个bean, 注入参数的属性名又和容器中 bean 的名称不一致。
就需要使用到@Qualifier来指定注入哪个名称的bean对象。
@Service
public class BookServiceImpl implements BookService {
//注解开发实现自动装配
@Autowired
@Qualifier("bookDaoImpl")
private BookDao bookDao;
public void save() {
bookDao.save();
System.out.println("Book Service save..");
}
}
注意 :@Qualifier 不能独立使用,必须和 @Autowired 一起使用
简单数据类型注入
使用 @Value 注解,将值写入注解的参数中就行了
@Component("bookDaoImpl")
public class BookDaoImpl implements BookDao {
@Value("zhangsan")
private String name;
public void save(){
System.out.println("book Dao save..");
}
@PostConstruct 在构造方法之后执行,替换 init-method
public void init(){
System.out.println("init..");
}
@PreDestroy //在销毁方法之前执行,替换 destroy-method
public void destory(){
System.out.println("destory..");
}
}
AOP
Aspect Oriented Programming ,即面向切面编程。
AOP是对面向对象编程的一个补充,它的目的是将复杂的需求分解为不同的切面,将散布在系统中的公共功能集中解决,它的实际含义是在运行时将代码切入到类的指定方法、指定位置上,将不同方法的同一个位置抽象为一个切面对象,并对该对象进行编程。
AOP的优点
- 降低模块之间的耦合度
- 使系统更容易扩展
- 更好的代码复用
- 非业务代码更加集中,不分散,便于统一管理
- 业务代码更加简洁纯粹,不掺杂其他的代码的影响