Spring的IOC和AOP

1 Sping简单介绍

1.1 Spring是什么

Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring
MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架。

1.2 Spring的优势

1.2.1 方便解耦,简化开发

通过 Spring 提供的 IoC 容器,可以将对象间的依赖关系交由 Spring 进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

1.2.2 AOP(面向切面编程)编程的支持

通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以通过 AOP 轻松应付。(例如打印日志、性能监控、事务管理、安全验证等等)。

1.2.3 声明式事务的支持

可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。

1.2.4 方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,使测试更容易实现。

1.2.5 方便集成各种优秀框架

Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。

1.3 Spring的体系结构

Spring体系结构

2 IOC

2.1 IOC(Inversion Of Control)

降低程序之间的耦合度(解耦)的思路有两种。一种是使用工厂模式,另一种就是Spring的IOC(控制翻转)。IOC将控制权从调用的类转换到了Spring的IOC容器,有Spring的IOC容器来创建实例依赖注入

2.2 IOC的配置方式

2.2.1 xml方式配置

下面以Idea为例具体说明。
首先新建一个Maven工程。在pom.xml文件中加入Spring依赖。

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.0.RELEASE</version>
  </dependency>

src>main文件夹下面新建resources文件夹,新建以 .xml结尾的配置文件。配置文件初始内容包括beans标签和xmlms。

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       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/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">    
</beans>

bean标签

bean的概念: 在计算机英语中,bean有可重复使用的组件的含义。Java Bean 指用Java语言编写的课重用组件。
作用: 用于配置对象让Spring来创建的。默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。
属性:
id 给对象在容器中提供一个唯一标识,用于获取对象。
class 指定类的权限定类名。用于反射创建对象。
scope 指定对象的作用范围。作用范围如下:

  • singleton:单例对象,默认值
  • prototype:多例的或者原型
  • request:WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中
  • session:WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中
  • globelSession:WEB 项目中,应用在 Portlet 环境.如果没有 Portlet 环境那么globalSession 相当于 session

init-method 指定类中的初始化方法名称
destroy-method指定类中的销毁方法名称
bean标签代码示例:

 <bean id="UserDao" class="com.xxxx.spring.dao.impl.UserDaoImpl"></bean>

bean的生命周期和作用域

单例对象:singleton

一个应用只有一个对象的实例。他的作用范围就是整个引用。
生命周期:
对象出生:当应用加载,容器创建时,对象就被创建了。
对象或者:只要容器在,对象就一直活着。
对象死亡:当容器销毁时,对象就被销毁了。

多例对象:prototype

每次访问对象时,都会重新创建实例。
生命周期
对象出生:当使用对象时,容器创建新的实例。
对象或者:只要对象在使用中,就一直活着。
对象死亡:当对象长时间未被使用时,就会被java的GC垃圾回收器回收了。

实例化bean的四种方式

第一种,使用默认的无参构造

在默认情况下,会根据舞草构造来实例化对象。如果没有无参构造,则会创建失败。

<bean id="UserDao" class="com.xxxx.spring.dao.impl.UserDaoImpl"></bean>
第二种,使用静态工厂方法创建
/**
*模拟一个静态工厂,创建业务层实现类
*/

public class StaticFactory {
	public static UserService createUserService(){
		return new UserServiceImpl();
	} 
}

使用 StaticFactory 类中的静态方法 createUserService 创建对象,并存入 spring 容器
id 属性:指定 bean 的 id,用于从容器中获取
class 属性:指定静态工厂的全限定类名
factory-method 属性:指定生产对象的静态方法

<bean id="userService" class="com.xxxx.spring.factory.StaticFactory" factory-mathod="createUserService"></bean>
第三种方式,Spring管理实例工厂,使用实例工厂的方法创建对象
/**
*模拟一个示例工厂,创建业务层实现类
此工厂创建实例对象,必须先有工厂实例对象,再调用方法创建对象
*/
public class InstanceFactory {
	public UserService createUserService(){
		return new UserServiceImpl();
	} 
}

bean:

<bean id="instanceFactory" class="com.xxxx.spring.factory.InstanceFactory"/>
<bean id="userService" 
	factory-bean="instanceFactory"
	factory-method="createUserService"></bean>

解释:先把工厂的创建交给 spring 来管理。然后再使用工厂的 bean 来调用里面的方法创建。
factory-bean 属性:用于指定实例工厂 bean 的 id。
factory-method 属性:用于指定实例工厂中创建对象的方法。

第四种方式,实现Spring的FactoryBean接口实例化
public class UserServiceInstance implements FactoryBean {
    @Override
    //获取对象的方法
    public Object getObject() throws Exception {
        return new UserServiceImpl();
    }

    @Override
    //获取对象的类型的方法
    public Class<?> getObjectType() {
        return UserService.class;
    }
}

bean:

<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" />

依赖注入的三种方式

依赖注入: Dependency Injection。它是 spring 框架核心 ioc 的具体实现。 前面我们通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。 ioc 解耦只是降低他们的依赖关系,并不是消除。例如:我们的业务层仍会调用持久层的方法。 那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。 简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取

第一种,set方法注入

此种方式注入,类中必须有需注入成员变量的set方法。用到标签为 property
用法示例:

<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" >
	<property name="userDao" ref="userDao"></property>
	<property name="name" value="admin"></property>
	<property name="age" value="21"></property>
</bean>

name: 找的是类中set方法后面的部分。
ref: 给类中成员赋值是其他bean类型的。
value: 给类中成员变量赋值是基本数据类型和String类型的。

List和Set类型的注入

<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" >
	<property name="jobs">
		<list>
             <value>秘书</value>
             <value>经理</value>
             <value>总监</value>
        </list>
	</property>
	
</bean>

Set类型相同,将标签换成标签即可。

Map类型的注入
使用标签,key和value为Map的key和value。

<property name="members">
   <map>
         <entry key="lidi" value="19"/>
         <entry key="lisy" value="22"/>
         <entry key="lucy" value="17"/>
         <entry key="lily" value="24"/>
     </map>
 </property>
第二种,构造器注入

就是使用类中的构造函数(有参构造函数),给成员变量赋值。但是,赋值的操作不再由我们自己来做,而是通过配置的方式,让 spring 框架来为我们注入。
涉及标签:
constructor-arg
属性:
name 指定参数咋构造函数中的名称。用这个名称去找给谁赋值。
index 指定参数再构造函数参数列表中的索引位置,从0开始。
type 指定参数再构造函数中的数据类型
value 可以给基本数据类型和String类型赋值
ref 他能赋的值是其他bean类型(必须是再配置文件中配置过的bean)
示例:

<bean id="userService" class="com.woniuxy.spring.UserServiceInstance" >
	<constructor-arg name="userDao" ref="userDao"></constructor-arg>
	<constructor-arg name="userName" value="lisa"></constructor-arg>
	<constructor-arg name="age" value="18"></constructor-arg>
	<constructor-arg name="hobby" >
		<list>
			<value>读书</value>
			<value>游泳</value>
			<value>敲代码</value>
		</list>
	</constructor-arg>	
</bean>
第三种方式,注解注入

此种方式会在后面注解配置方式中说明。

2.2.2.2 注解方式配置IOC

说明:此种方式仍然需要xml配置文件,需要再里面添加如下标签:
作用是告知Spring在创建容器时,要扫描的包。

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

注解分类

  1. 用于创建对象的
  2. 用于注入数据的
  3. 用于改变作用范围的
  4. 和生命周期相关的

1.用于创建对象的
@Component:
作用:用于把当前类对象存入Spring容器中,属性 value 用于指定beande id ,当不写是,默认为当前类名,且首字母小写
@Service
@Controller
@Ropository
上面是Spring专为三层架构指定的注解,作用和@Component相同

2.用于注入数据的
@Autowired
作用:自动按照数据类型注入。只要容器中有唯一一个bean对象的数据集类型和要注入的变量的数据类型匹配,就可以注入成功。
出现位置:可以在变量上,也可以在方法上。
说明:使用注解方式注入时,set方法不是必须的。
如果IOC容器中没有任何bean的类型和要注入的变量类型匹配,则报错。如果有多个bean的类型和要注入的变量类型匹配,则看bean的id和要注入的变量名称是否相同,如果相同就注入,没有相同的,则报错。
@Qualifier
作用:再按照类型的基础上再按照变量名称注入。再给类成员注入时,必须要和@Autowired一起使用。再给方法注入时,可以单独使用。
属性:value 用于指定注入bean的id。
@Resource
作用:直接按bean的id注入,可以单独使用
属性:name,用于指定bean的id

说明:以上三种注入方式都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。另外,集合类型的注入只能通过xml配置来实现。
@Value
作用:用于注入基本类型和String类型的数据。
属性:value,用于指定数据的值。注解中的value="" value可以省略。直接写成@Value(“lisa”)。可以使用Spring的SPEL表达式。写法:${}

3.用于指定bean的作用范围
@Scope
属性: value,指定范围的取值,常用:Singleton(单例)和Prototype(多例)。

4.生命周期
@PostConstruct 用于i指定初始化方法
@PreDestroy 用于指定销毁方法

2.2.2.3 用Java代码方式配置IOC

注解: @Bean @Configuration @ComponentScan

  • @Configuration 标记一个类为配置类
  • @Bean 标记某个方法返回值为spring的bean,方法参数为依赖注入的请求

代码示例:

@Configuration
public class Config {

    @Bean
    public UserService userService(){
        UserServiceImpl userService = new UserServiceImpl();
//        外部依赖注入
        userService.setUserDao(userDao());
        return userService;
    }

    @Bean
    public UserDao userDao(){
        //将QueryRunner对象注入UserDao
        UserDaoImpl userDao = new UserDaoImpl();
       // userDao.setQr(queryRunner());
        return userDao;
    }

    @Bean
    public UserController userController(){
        UserController userController = new UserController();
        //依赖注入,采用设置属性的方法
        userController.setUserService(userService());
        return userController;
    }
}

2.2.2.4 用包扫描方式配置IOC

@Configuration 标记一个类为配置类 等价于配置文件: applicationContext.xml

@ComponentScan 打开包扫描功能,并且指定扫描的包 等价于 <context:component-scan base-package=“xxx”>

加入@Controller…@Autowired 等注解

如要配置数据库连接,需要引用配置文件可用下面方式引入:
@PropertySource("{配置文件位置}")

2.2.2.5 Java配置和注解混合使用

在注解类上可以用@Import导入Java配置,用ImportResource导入xml配置
@Import(AppConfig.class)
@ImportResource(“applicationContext.xml”)

3 AOP(Aspect Oritented Programming) 面向切面编程

3.1.1 什么是AOP

简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的
基础上,对我们的已有方法进行增强。

3.1.2 AOP的作用和优势

作用:在程序运行期间,不修改源码,对已有方法进行增强
优势:减少重复代码,提高开发效率,方便维护

3.1.3 AOP的实现方式

使用动态代理技术

3.1.4 AOP的应用实例

打印日志、性能监控、事务管理、安全验证等等。

3.2.1 AOP的一些名词

  • 连接点:JoinPoint,需要加入功能的位置,一般是方法。
  • 切入点:Pointcut,真正执行加入功能的连接点。
  • 通知:Advice,需要实现的功能。
  • 切面:Aspect, Java语言中,将切入点和通知等组装在一起的代码单元。
  • 目标对象:Target, 要操作的对象。
  • 织入:Weave ,将功能加入到切入点中的过程。

通知类型:

  • 前置通知 : 方法执行之前 MethodBeforeAdvice
  • 后置通知 : 方法执行之后 AfterReturningAdvice
  • 环绕通知 : 方法执行前后 MethodInterceptor
  • 异常通知 : 抛出异常时
  • 最终通知 : finally执行时

3.2.2 xml配置AOP的步骤

1) 编写service类

2) 编写通知 , 实现MethodBeforeAdvice接口

//method 要执行的方法
// args 方法的参数
// target 方法所在的对象
public void before(Method method, Object[] args, Object target) throws Throwable {
    }

3)配置xml

  • 配置service
  • 配置通知
  • 配置切入点,class= org.springframework.aop.support.JdkRegexpMethodPointcut ,配置属性pattern=> service的方法
  • 配置切面,class=org.springframework.aop.support.DefaultPointcutAdvisor 连接切入点和通知
  • 包装service类, class= org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
  • 获取bean,调用方法,将会看到通知执行了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--目标对象-->
    <bean id="userService" class="com.woniuxy.spring.aop.service.impl.UserServiceImpl"/>
    <!--通知: 实现了打日志的功能-->
    <bean id="beforeExecution" class="com.woniuxy.spring.aop.component.BeforeExecution"/>

    <!--切入点:选出了需要增加功能的方法-->
    <bean id="pointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
        <property name="pattern" value="com.woniuxy.spring.aop.service.impl.UserServiceImpl.addUser"/>
    </bean>

    <!--切面:连接切入点和通知,让打日志功能在切入点的位置执行-->
    <bean id="aspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="pointcut" ref="pointCut"/>
        <property name="advice" ref="beforeExecution"/>
    </bean>

    <!--包装userService-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>


</beans>

关于切面的配置

<aop:config>
    <aop:aspect ref="txAdvice">
        <!--切入点-->
        <aop:pointcut id="servicePointcut" expression="execution(* com.woniuxy.spring.aop.service.impl.*.*(..))"/>
        <!--通知-->
        <!--前置--><aop:before method="begin" pointcut-ref="servicePointcut"/>
        <!--后置--><aop:after-returning method="commit" pointcut-ref="servicePointcut"/>
        <!--异常--><aop:after-throwing method="rollback" pointcut-ref="servicePointcut"/>
    </aop:aspect>
</aop:config>

注解式配置AOP

@Aspect

@Pointcut

@Around @Befrore @After @AfterReturning @AfterThrowing

@EnableAspectJAutoProxy

代码示例:

/**
 * 用另一种方式,用java代码代替xml配置文件,调用时对应App类中的第二种方法
 */
@Configuration
@ComponentScan("com.woniuxy.spring.aop")
@EnableAspectJAutoProxy
public class AopConfig {
}
@Component
@Aspect
public class TxAspect {
	//配置切入点
    @Pointcut("execution(* com.woniuxy.spring.aop.service.impl.*.*(..))")
    public void servicePointcut(){}

    @Around("servicePointcut()")//通知类型
    public Object aroundAdvice(ProceedingJoinPoint pjp){
        Object args[] = pjp.getArgs();
        Object res = null;
        try{
            System.out.println("开启事务");
            res = pjp.proceed(args);
            System.out.println("提交事务");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("回滚事务");
        }
        return res;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值