JavaEE—2.Spring

本文介绍了Spring框架的核心特性,包括IOC(控制反转)和AOP(面向切面编程)。Spring通过IOC管理对象的生命周期和依赖关系,降低了代码耦合度。AOP则提供了在不修改原有代码的情况下,插入公共行为的能力,常用于日志、事务处理等场景。文章详细讲解了Spring中bean的创建方式,如配置文件、静态工厂、实例工厂以及注解方式,并阐述了Spring获取bean的不同方法。此外,还探讨了IOC的原理和作用,以及DI(依赖注入)的概念。最后,文章介绍了AOP的基本概念和Spring AOP的实现方式,包括代理类型和编程要点。
摘要由CSDN通过智能技术生成

1.Spring框架存在的意义

1.解决了什么问题

Spring是一个开源框架,Spring为简化企业级开发而生,使用Spring,JavaBean就可以实现很多以前要靠EJB才能实现的功能。同样的功能,在EJB中要通过繁琐的配置和复杂的代码才能够实现,而在Spring中却非常的优雅和简洁。

将创建对象的任务交给IOC容器(注解+反射),使用对象时通过依赖注入实现

2.如何解决的

在这里插入图片描述

Spring是一个IOC(DI)和AOP容器框架

Spring的优良特性:

  • 1)IOC:说白了就是将创建对象的过程或者说创建对象的权限交给了spring框架来帮进行处理,程序员再不用通过new的方式来手动创建Javabean对象,这个过程就叫做控制反转。其实就是通过反射创建对象

  • 2)依赖注入:DI——Dependency Injection,反转控制(IOC)最经典的实现。

    • DI(dependency injection) 依赖注入
      就是使用spring框架为JavaBean的属性赋值的过程
      可以实现解耦:即使用多态——将“接口引用”指向”注入对象”的引用
    • IOC与DI的区别:
      1:IOC是为我们创建对象。DI是我们创建对象后的属性赋值
      2:先有IOC,才能够使用DI
  • 3)面向切面编程:Aspect Oriented Programming——AOP

    • 将公共的代码抽取出来,放到类中(即切面)
    • 使用动态代理,应用到代码要使用的地方
  • 4)一站式:在IOC和AOP的基础上,可以整合各种企业应用的开源框架和优秀的第三方类库(实际上Spring 自身也提供了表述层(Web层)的SpringMVC和持久层的Spring JDBC)。

Spring中创建bean

1.依据配置文件创建对象

在applicationContext.xml中加入配置,调用无参构造器(或者缺省构造器) 创建对象:

step1:为类添加无参构造器(内部有了这个无参构造的类就可以省略这一步)

step2:配置文件中添加一个bean元素

<!-- 配置UserBean1的初始化 -->
<bean id="userBean1" class="cn.itcast.spring.demo2.UserBean1">
</bean>

step3:启动创建容器,调用容器的getBean方法就是实例化这个类返回对象<—重要思想!!!

public class UserDaoTest {

	@Test
	public void testHello() {
		// 原来创建Bean的方式
		// UserDao userDao = new UserDaoImpl();
		// userDao.hello();

		// ApplicationContext是Spring容器的一个子接口
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		UserDaoImpl userDao = (UserDaoImpl) context.getBean("userDao");
		userDao.hello();

		System.out.println(userDao.getUsername());
	}
}

2.静态工厂

方式二: 用静态工厂方法创建—解决抽象类

待创建的对象

public class UserBean2 {

	public void hello() {
		System.out.println("Hello Spring UserBean2");
	}
}

工厂

public class UserBean2Factory {

	public static UserBean2 createUserBean2(){
		return new UserBean2();
	}
}

applicationContext.xml中的配置

<bean id="userBean2" class="cn.itcast.spring.demo2.UserBean2Factory"
	factory-method="createUserBean2">
</bean>

测试:

@Test
public void testUserBean2() {
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	UserBean2 userBean2 = (UserBean2) context.getBean("userBean2");
	userBean2.hello();
}

3.实例工厂

待创建的对象:

public class UserBean3 {

	public void hello() {
		System.out.println("Hello Spring UserBean3");
	}
}

实例工厂

public class UserBean3Factory {

	public UserBean3 createUserBean3(){
		return new UserBean3();
	}
}
<!-- 通过实例工厂方式创建对象 -->
<!-- 配置实例工程 -->
<bean id="userBean3Factory" class="cn.itcast.spring.demo2.UserBean3Factory">
</bean>
<!-- 配置Bean -->
<bean id="userBean3" class="cn.itcast.spring.demo2.UserBean3"
	factory-bean="userBean3Factory" factory-method="createUserBean3">
</bean>
@Test
public void testUserBean3() {
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
	UserBean3 userBean3 = (UserBean3) context.getBean("userBean3");
	userBean3.hello();
}

4.基于注解的方式配置bean

1.常用的注解

  • @Component:标识一个普通组件

  • @Repository:标识一个持久化层的组件

  • @Service:标识一个业务逻辑层的组件

  • @Controller:标识一个表现层的组件

  • @Autowired:

    • 设置类中需要自动装配的属性
    • 添加了该注解的属性默认必须装配成功,否则会抛出异常
    • 如果要设置某个属性可以不装配,可以设置该注解中的required的属性值是false
  • @Qualifier

    • 通过该注解的value属性设置根据哪个id实现自动装配

2.使用注解的方式配置bean的步骤:

1)在类上添加对应的注解

  • 不带属性的类
/*
 * 添加了注解的类会交给Spring的IOC容器管理,默认在IOC容器中的bean的id是类的首字母小写,
 * 我们也可以通过注解的value属性来指定该id,value的属性名可以省略
 */
//@Repository(value="userDao")
@Repository("userDao")
public class UserDaoImpl implements UserDao {
  • 带属性的类
@Service("userService")
public class UserServiceImpl implements UserService {
    /*
     * 自动装配的步骤:
     *  1.根据属性的类型实现自动装配
     *  2.以属性名作为id从IOC容器中寻找
     *  3.我们还可以通过@Qualifier注解的value属性来指定根据那个id实现自动装配
     *
     */
    @Qualifier(value="userDao2")
    @Autowired
    private UserDao userDao;

    /*
     * 添加了@Autowired注解的属性默认必须装配成功,否则会抛出异常,
     * 我们可以通过指定@Autowired注解中的required属性值为false来告诉Spring当前属性可以不装配
     */
    @Autowired(required=false)
    private User user;

2)在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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!-- 设置自动扫描的包
        base-package属性:设置一个基础包,Spring会自动扫描该包及其子包
    -->
    <context:component-scan base-package="com.mytest.spring.annotation"></context:component-scan>
</beans>

1.spring的bean容器相关的注解

1)@Autowired 是我们使用得最多的注解,其实就是 autowire=byType 就是根据类型的自动注入依赖(基于注解的依赖注入),可以被使用再属性域,方法,构造函数上。

2)@Qualifier 就是 autowire=byName, @Autowired注解判断多个bean类型相同时,就需要使用 @Qualifier(“xxBean”) 来指定依赖的bean的id:

案例:

@Controller
@RequestMapping("/user")
public class HelloController {
    @Autowired
    @Qualifier("userService")
    private UserService userService;
    ......
}

3)@Resource 属于JSR250标准,用于属性域额和方法上。也是 byName 类型的依赖注入。使用方式:@Resource(name=“xxBean”). 不带参数的 @Resource 默认值类名首字母小写。

4)JSR-330标准javax.inject.*中的注解(@Inject, @Named, @Qualifier, @Provider, @Scope, @Singleton)。@Inject就相当于@Autowired, @Named 就相当于 @Qualifier, 另外 @Named 用在类上还有 @Component的功能。

5)@Component, @Controller, @Service, @Repository, 这几个注解不同于上面的注解,上面的注解都是将被依赖的bean注入进入,而这几个注解的作用都是生产bean, 这些注解都是注解在类上,将类注解成spring的bean工厂中一个一个的bean。@Controller, @Service, @Repository基本就是语义更加细化的@Component。

6)@PostConstruct 和 @PreDestroy 不是用于依赖注入,而是bean 的生命周期。类似于 init-method(InitializeingBean) destory-method(DisposableBean)

2.spring中注解的处理

spring中注解的处理基本都是通过实现接口 BeanPostProcessor 来进行的:

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

相关的处理类有:AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor

这些处理类,可以通过 context:annotation-config/ 配置隐式的配置进spring容器。这些都是依赖注入的处理,还有生产bean的注解(@Component, @Controller, @Service, @Repository)的处理

<context:component-scan base-package="com.mytest.spring.helloworld"/>

这些都是通过指定扫描的基包路径来进行的,将他们扫描进spring的bean容器。注意context:component-scan也会默认将 AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor 配置进来。所以context:annotation-config/是可以省略的。另外context:component-scan也可以扫描@Aspect风格的AOP注解,但是需要在配置文件中加入 aop:aspectj-autoproxy/ 进行配合。

Spring获取bean的方式

1)根据bean的名称(id属性值)获取
2)根据bean的类型获取,但要保证IOC容器中该类型的bean是唯一的,否则会抛出异常

/*
* ★获取bean的方式:
*  1)根据bean的名称(id属性值)获取
*  2)根据bean的类型获取
*      -注意:一定要保证IOC容器中该类型的bean是唯一的,否则会抛出异常
*/
//根据bean的名称(id属性值)获取
HelloWorld helloWorld = (HelloWorld) ioc.getBean("helloWorld");
//根据bean的类型获取
HelloWorld helloWorld2 = ioc.getBean(HelloWorld.class);

Spring的作用:

a.简化开发:spring对常用的API都做了一些简化和封装(比如,用spring jdbc访问数据库,就不用考虑如何获取连接和关闭连接)。

b.解耦:spring帮我们管理对象的依赖关系,这样对象间的耦合度低,方便维护。

c.集成其他框架:spring可以将其他的框架集成进来。(比如可以将Mybatis等框架集成进来)

1.1 ioc是什么?
IOC——:inversion of control,即“控制反转”,ioc不是一种技术,是一种设计思想,一个重要的面向对象编程的法则。在java开发中,IOC意味着将你设计好的对象交给容器控制,而不是在传统的在你的对象内部直接控制。
何为“控制”:传统的JAVA SE程序设计,我们是从对象内部通过new创建对象,是程序控制对象的创建,而IOC有一个专门的容器(IOC容器)创建对象,IOC容器控制外部资源的获取(包括对象,文件等)。

何为“反转”:传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,即“正转”。而“反转”,是由容器来帮我们去创建及注入依赖对象。对象只是被动的接受依赖对象。依赖对象的获取被反转了。

1.2 ioc有什么用?
ioc容器能帮我们管理对象的依赖关系,这样对象与对象的耦合度低,方便代码的维护。对于spring框架来说,ioc就是由spring来负责控制对象的生命周期和对象间的关系。

1.3 DI
DI——dependenc injection,即“依赖注入”。IOC与DI有什么关系呢?其实它们是同一个概念的不同角度描述。“依赖注入”,相对ioc而言,“依赖注入”明确地描述了“被注入对象”依赖ioc容器配置依赖对象。IOC的一个重点是在系统运行中,动态的向某个对象提供所需要的其他对象,这一点通过DI实现。DI如何实现?这就要引入java 1.3之后的一个重要特征——反射(reflection)。它允许程序在运行的时候动态生成对象、执行对象的方法、改变对象的属性。spring就是通过反射注入的。

2.1 AOP?

2.1.1 Aop是什么?
AOP——(Aspect-Oriented Programming),即面向切面编程。AOP可以说是OOP的补充和完善,是Spring框架核心功能之一。
2.1.2 AOP的特点(优势)?
为了解决当我们需要为分散的对象引入公共行为的时候,如程序中交叉业务逻辑(系统日志,事务处理,系统安全验证,系统数据缓存等等),这是我们应当把它封装成一个切面,注入到目标对象(具体逻辑)中去。可以简化代码开发和效率,能够在不改变原有代码的基础上扩展新的功能实现。

2.1.3AOP 核心概念、术语
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。其相关概念术语如下:
切面(aspect): 横切面对象,一般为一个具体类对象(本质就是加了@Aspect注解的类)
通知(advice):拦截到连接点之后只要执行的方法
切入点(pointcut):对连接点拦截内容的一种定义
连接点(joinpoint):程序执行过程中某个特定的点,一般指被拦截到的的方法
目标对象(target):代理的目标对象。
通知(Advice):在切面的某个特定连接点上执行的动作,例如before,after等

知识点术语强化:

  1. 切面(可以简单理解为要植入的新的业务功能,这个功能交给某个类负责,这个类就是切面)
  2. 通知(可以简单理解为一个业务中的扩展逻辑的若干步骤,例如先做什么(before),再做什么(afterReturn),最后做什么)
  3. 切入点(在原有的哪些业务方法上扩展新的业务,可以将切入点理解为方法的集合)
  4. 连接点(可以简单理解为切入点中的一个具体方法)
  5. 目标对象(需要扩展功能的那个对象,一般为被代理对象)
  6. 代理对象(负责调用切面中的方法为目标对象植入新的功能)

2.1.4 Spring AOP 的编程实现
Spring中AOP代理由Spring的IOC容器负责生成、管理。
其依赖关系也由IOC容器负责管理。
因此,AOP代理可以直接使用容器中的其它bean实例作为目标,
这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理。

AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

  1. 定义普通业务组件(切面)
  2. 定义切入点,一个切入点可能横切多个业务组件
  3. 定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作。
    所以进行AOP编程的关键就是定义切入点和定义增强处理,一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理

3.还有什么可改进之处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值