Spring简单详解

简介

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的生命周期

  1. Bean容器找到配置文件Spring Bean的定义
  2. Bean容器利用Java反射创建一个Bean的实例
  3. 如果涉及到一些属性值,利用set()方法设置一些属性值
  4. 如果Bean实现了BeanNameAware接口, 调用setBeanName()方法
  5. 如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法
  6. 和上面类型,如果实现了xxxAware接口,调用相应的接口
  7. 如果有加载这个Bean的容器实现了BeanPostProcessor接口,执行postProcessBeforeInitialization()方法
  8. 如果Bean实现了InitializingBean接口,调用afterPropertiesSet()方法
  9. 如果Bean在配置文件中定义 init-method 属性,指定执行的方法
  10. 如果有加载这个Bean的容器实现了BeanPostProcessor接口,执行postProcessAfterInitialization()方法
  11. 当销毁Bean的时候, 如果Bean实现了DisposableBean 接口,执行destroy()方法
  12. 当销毁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规范

    1. 默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class)
    2. 如果找到多个相同的类型的组件,再将属性的名称作为组件的id去容器中查找
    3. @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);
        }
    }
    

猜你喜欢

转载自blog.csdn.net/qq_33460865/article/details/109196811