简介
Spring 是一种轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。Spring 包括很多的模块。比如:
- Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IoC 依赖注入功能。
- Spring Aspects : 该模块为与AspectJ的集成提供支持。
- Spring AOP :提供了面向切面的编程实现。
- Spring JDBC : Java数据库连接。
- Spring JMS :Java消息服务。
- Spring ORM : 用于支持Hibernate等ORM工具。
- Spring Web : 为创建Web应用程序提供支持。
- Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。
IoC(控制反转) & AOP(面向切面)
IoC是Spring最重要的特性之一。控制反转,简单地说就是,创建对象控制权交由Spring来管理,我们不需要手动去创建对象,Spring对自动帮我们创建好。大大的简化了我们应用的开发。
AOP(面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护。AOP是基于动态代理的实现的 ,可以去了解这个设计模式。
Bean作用域(默认单例)
- prototype: 每次获取的时候才会调用方法创建bean。
- singleton: IoC容器启动会调用方法创建对象放到IoC容器中,这样每次获取都是相同的。
- request: 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。
- session: 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。
单例Bean是存在线程安全问题的,当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。解决办法:可以使用ThreadLocal解决
工厂Bean
// 创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
// 返回一个Color对象,这个对象会添加到容器中
@Override
public Color getObject() throws Exception {
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
// true 是单实例 false 是多实例
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
public class MainConfig {
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
}
public class MainTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] definitionNames = applicationContext.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
// 工厂Bean获取的是getObject()创建的对象
Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
System.out.println(colorFactoryBean.getClass()); // class com.aloneness.bean.Color
// 如果需要获取工厂Bean,需要加上前缀&
Object colorFactoryBean1 = applicationContext.getBean("&colorFactoryBean");
System.out.println(colorFactoryBean1.getClass()); // class com.aloneness.bean.ColorFactoryBean
}
}
Bean的生命周期
Bean的生命周期: 创建—初始化—销毁的过程, 容器管理bean的生命周期
- Bean容器找到配置文件Spring Bean的定义
- Bean容器利用Java反射创建一个Bean的实例
- 如果涉及到一些属性值,利用set()方法设置一些属性值
- 如果Bean实现了BeanNameAware接口, 调用setBeanName()方法
- 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法
- 和上面类型,如果实现了xxxAware接口,调用相应的接口
- 如果有加载这个Bean的容器实现了BeanPostProcessor接口,执行postProcessBeforeInitialization()方法
- 如果Bean实现了InitializingBean接口,调用afterPropertiesSet()方法
- 如果Bean在配置文件中定义 init-method 属性,指定执行的方法
- 如果有加载这个Bean的容器实现了BeanPostProcessor接口,执行postProcessAfterInitialization()方法
- 当销毁Bean的时候, 如果Bean实现了DisposableBean 接口,执行destroy()方法
- 当销毁Bean的时候, 如果Bean在配置文件中定义了destroy-method 属性,指定执行的方法
生命周期 | 创建 | 初始化 | 销毁 |
---|---|---|---|
单实例 | 容器启动的时候创建 | 创建对象完成,赋值后调用初始化方法 | 容器关闭调用销毁方法 |
多实例 | 获取Bean的时候创建 | 创建对象完成,赋值后调用初始化方法 | 容器不会管理这个Bean,不会调用销毁方法 |
- 自定义初始化方法和销毁方法,通过@Bean注解初始化和销毁
public class Car {
public Car(){
System.out.println("car constructor...");
}
public void init(){
System.out.println("car init()...");
}
public void destory(){
System.out.println("car destory()...");
}
}
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init", destroyMethod = "destory")
public Car car(){
return new Car();
}
}
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
applicationContext.close();
}
}
// 结果为
car constructor...
car init()...
容器创建完成...
car destory()...
- 自定义初始化方法和销毁方法,通过InitializingBean、DisposableBean接口定义初始化,销毁方法
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat(){
System.out.println("cat...构造器...");
}
// 初始化, Bean创建完成,并赋值好后
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet...初始化...");
}
// 销毁方法
@Override
public void destroy() throws Exception {
System.out.println("destroy...销毁...");
}
}
@Configuration
@ComponentScan("com.aloneness.lifeCycle")
public class MainConfigOfLifeCycle {
}
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
applicationContext.close();
}
}
// 结果为
cat...构造器...
afterPropertiesSet...初始化...
容器创建完成...
destroy...销毁...
- 自定义初始化方法和销毁方法,可以使用JSR250的@PostConstruct和@PreDestory注解
@Component
public class Dog {
public Dog(){
System.out.println("Dog constructor...");
}
@PostConstruct
public void init(){
System.out.println("Dog...init...");
}
@PreDestroy
public void destroy(){
System.out.println("Dog...destory");
}
}
public class MainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成...");
applicationContext.close();
}
}
// 结果为
Dog constructor...
Dog...init...
容器创建完成...
Dog...destory
BeanPostProcessor接口,Bean的后置处理器,用来处理Bean初始化前后的工作
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
/**
* @param o bean实例
* @param s bean的名字
* @return 返回bean对象
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("postProcessBeforeInitialization...初始化前..." + s + "-->" + o);
return o;
}
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("postProcessAfterInitialization...初始化后..." + s + "-->" + o);
return o;
}
}
// 结果为
cat...构造器...
postProcessBeforeInitialization...初始化前...cat-->com.aloneness.lifeCycle.Cat@101df177
afterPropertiesSet...初始化...
postProcessAfterInitialization...初始化后...cat-->com.aloneness.lifeCycle.Cat@101df177
Aware接口
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory等等)自定义组件实现xxxAware接口 xxxAware:功能使用xxxProcessor
Spring继承AspectJ实现AOP
- 引入AspectJ依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
- 定义一个业务类
public class Calculator {
public int div(int i, int j) {
return i / j;
}
}
- 定义一个切面类
@Aspect
public class LogAspects {
/**
* 切点,目标方法
*/
@Pointcut("execution(public int com.aloneness.spring.study.aop.Calculator.*(..))")
public void pointCut() {
}
/**
* 前置通知
*
* @param joinPoint
*/
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(joinPoint.getSignature().getName() + " 除法运行... 参数列表是..." + Arrays.asList(args));
}
/**
* 后置通知
*
* @param joinPoint
*/
@After("pointCut()")
public void logEnd(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName() + " 除法结束... ");
}
/**
* 返回通知
*
* @param result
*/
@AfterReturning(value = "pointCut()", returning = "result")
public void logReturn(Object result){
System.out.println("除法正常返回..." + result);
}
/**
* 异常通知
*
* @param exception
*/
@AfterThrowing(value = "pointCut()", throwing = "exception")
public void logException(Exception exception){
System.out.println("除法异常..." + exception);
}
/**
* 环绕通知
*
* @param joinPoint
* @return
*/
@Around("pointCut()")
public Object logAround(ProceedingJoinPoint joinPoint){
Object result = null;
try{
// 得到方法执行所需的参数
Object[] args = joinPoint.getArgs();
System.out.println("LogAspects类中的logAround方法开始记录日志了...前置" +
joinPoint.getSignature().getName() + "-->" + Arrays.asList(args));
// 明确调用业务层方法(切入点方法)
result = joinPoint.proceed(args);
System.out.println("LogAspects类中的logAround方法开始记录日志了...后置" +
joinPoint.getSignature().getName() + "-->" + Arrays.asList(args));
return result;
}catch (Throwable t){
System.out.println("LogAspects类中的logAround方法开始记录日志了...异常");
throw new RuntimeException(t);
}
}
}
- 开启AOP配置,并将两个类注册为Bean
@Configuration
@EnableAspectJAutoProxy
public class AOPConfig {
@Bean
public Calculator calculator() {
return new Calculator();
}
@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}
- 测试AOP切面
public class AOPTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AOPConfig.class);
Calculator calculator = applicationContext.getBean(Calculator.class);
calculator.div(4, 2);
}
}
结果
LogAspects类中的logAround方法开始记录日志了...前置div-->[4, 2]
div 除法运行... 参数列表是...[4, 2]
LogAspects类中的logAround方法开始记录日志了...后置div-->[4, 2]
div 除法结束...
除法正常返回...2
Spring框架的设计模式
- 工厂设计模式:通过BeanFactory、ApplicationContext创建Bean
- 单例模式:Spring的Bean默认都是单例
- 代理模式:SpringAOP的实现
- 模板方法:容器刷新refresh()函数
Spring注解大全
-
@Scope 设置Bean的作用域
-
@Lazy 懒加载,容器启动不创建,第一次使用的时候才会创建对象,并初始化
-
@Conditional 按条件注册Bean,比如根据不同的操作系统来创建Bean
-
@Value 赋值,引入配置文件的值 ${}。可以和@PropertySource配合
-
@PropertySource 引入配置文件@PropertySource(value = {“classpath:person.properties”})
-
@ComponentScan 组件扫描,配合@Controller/@Service/@Reponitory/@Component注解,给容器注册Bean
-
@Configuration 表明这个类是配置类,相当于一个xml配置文件,配置@Bean注解,给容器注册Bean
-
@Qualifier 如果注入的时候多个同类型的Bean,可以使用@Qualifier()指定注入哪一个Bean
-
@Primary 注入的时候可以优先使用这个Bean装配
-
@Autowired 自动注入,支持使用@Resource(JSR250) @Inject(JSR330) Java规范
- 默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class)
- 如果找到多个相同的类型的组件,再将属性的名称作为组件的id去容器中查找
- @Qualifier(“bookDao”):使用@Qualifier指定需要装配的组件的的名称,而不是使用属性名
-
@Profile 动态的激活和切换不同的环境
- 命令行参数 -Dspring.profiles.active=test\dev\prod
- 使用代码的方式激活
@Configuration public class MainConfigOfProfile { @Profile("dev") @Bean public DataSource devDataSource() throws PropertyVetoException { ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setUser("root"); comboPooledDataSource.setPassword("123456"); comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver"); comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/myshop"); return comboPooledDataSource; } @Profile("prod") @Bean public DataSource prodDataSource() throws PropertyVetoException { ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setUser("root"); comboPooledDataSource.setPassword("123456"); comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver"); comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/myshop"); return comboPooledDataSource; } }
-
@Import 快速给容器中的导入一个组件
- @Import(要导入到容器中的组件), 容器中就会自动注册这个组件,id默认是全类名
@Configuration @Import(value = {Test01.class, Test02.class}) public class MainConfig { @Bean(value = "person") public Person person01(){ return new Person("zhangsan", 23); } }
- ImportSelector接口: 返回需要导入的组件的全类名
// 返回需要导入的组件 public class MyImportSelector implements ImportSelector { /** * AnnotationMetadata 当前标注@Import注解类的所有注解信息 * * @param importingClassMetadata * @return */ @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // 不要返回null值,会报空指针异常 return new String[]{"com.aloneness.bean.Test03", "com.aloneness.bean.Test04"}; } } @Configuration @Import(value = {Test01.class, Test02.class, MyImportSelector.class}) public class MainConfig { @Bean(value = "person") public Person person01(){ return new Person("zhangsan", 23); } }
- ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * 把所有需要添加到容器中的bean, 调用BeanDefinitionRegistry.registerBeanDefinition() 手工注册进来 * * @param importingClassMetadata AnnotationMetadata 当前类的注册信息 * @param registry BeanDefinitionRegistry BeanDefinition的注册类 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean definition = registry.containsBeanDefinition("com.aloneness.bean.Test03"); boolean definition1 = registry.containsBeanDefinition("com.aloneness.bean.Test04"); if(definition && definition1){ RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Test05.class); registry.registerBeanDefinition("test05", rootBeanDefinition); } } } @Configuration @Import(value = {Test01.class, Test02.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig { @Bean(value = "person") public Person person01(){ return new Person("zhangsan", 23); } }