Spring入门(二)— IOC注解、Spring测试AOP入门

一、Spring整合Servlet背后的细节

1. 为什么要在web.xml中配置listener

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

配置listener主要是为了捕获项目发布 | 服务器启动的契机 ,为了解析xml , 创建工厂。 这个listener是spring官方提供的,里面已经具备了解析xml 和 创建工厂的代码。

2. 为什么要在web.xml中配置context-param

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

正如上面所说的,listener捕获到了项目发布的契机,进而去创建工厂。但是创建工厂需要解析xml 。 spring的这个监听器里面,默认会到WEB-INF/applicationContext.xml. 如果不想放置到这个位置,可以通过一个context-param来告诉spring,我们的配置文件在哪里。 classpath 表示这个文件是位于类路径底下。 classes目录

3. 为什么使用工具类也能拿到工厂,到底工厂放在了哪里?  

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

    //项目一发布,就执行
    public void contextInitialized(ServletContextEvent event) {
        //创建工厂
        initWebApplicationContext(event.getServletContext());
    }
}
?
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        ...
        if (this.context == null) {
             //创建工厂
             this.context = createWebApplicationContext(servletContext);
        }

 //把创建好的工厂,存储到作用域      //servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
        this.context);
        ...
    }
?
//spring为了简化程序员获取工厂的工作, 就提供了一个工具类,其实这个工具类就是对取值的代码进行封装
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

//ApplicationContext context = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
?

二、IOC注解

1. 注解入门

  1. 导入jar包

    spring-aop-xxx.jar

  2. 导入约束
<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        http://www.springframework.org/schema/context/spring-context.xsd"> 
  1. 在xml里面打开注解扫描开关
<!-- 告诉spring要去解析类,因为类上有注解 -->
<context:component-scan base-package="com.pri.service.impl"/>
  1. 在托管的类上打注解
@Component("us")
public class UserServiceImpl implements UserService {
    ...
}
  1. 问工厂要实例对象
//创建工厂 创建工厂,需要解析xml ,所以要传递进去xml文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

//问工厂要实例对象
UserService userService = (UserService) context.getBean("us");

//调用方法
userService.save();

//关闭工厂 : 以后我们几乎不会关闭工厂。
((AbstractApplicationContext) context).close();

2. 注解创建对象

/*
 1. @Component组件,表示要托管这个类,让spring创建这个类的实例。 括号里面的us 其实就是id标识符
 2. @Component 是通用的注解, 对任何托管的类都可以使用,但是spring为了迎合三层架构,所以对每一层
 也给出了具体的注解。
        Action  --- @Controller
        Service --- @Service
        Dao --- @Repository :仓库,
    建议: 如果以后托管三层中的类,请使用具体对应的注解,如果托管的是普通的其他类。@Component
 3. 默认生成的实例还是单例,如果想做成多例,那么还得添加一个注解
        @Scope("prototype")
 4.  @PostConstruct  //初始化实例的时候调用
     @PreDestroy  //销毁实例之前,调用
 5. 如果使用注解托管某一个类,不写属性值,那么默认的id标识符就是类的名字(首字母是小写) userServiceImpl
 6.<!-- 如果想要扫描多个包,就写一个通用的前缀即可 -->
<context:component-scan base-package="com.itheima"/>
*/

3. DI注解开发(注入对象)

使用注解来完成依赖注入。 一般注解注入,它针对的点是对象的注入。 spring针对对象的注入,提供了两个注解 @Resource@Autowired

  • 常用的注解就两个 @Resource & @Autowired

@Resource(name="ud") 根据给定的标记找到对应的类,创建对象,注入进来。

@Autowired 自动装配,会找到对应的实现类创建对象,注入进来。但是如果存在多个实现,那么会抛出异常

@Repository("ud")
public class UserDaoImpl implements UserDao {
}

public class UserServiceImpl implements UserService {
    @Resource(name="ud") //spring拿着ud找到具体的类,然后创建实例,注入进来。
    private UserDao userDao;
    ...
}
----------------------------------------------------------
public class UserServiceImpl implements UserService {
     @Autowired  //自动装配 根据注入的接口类型找到对应的实现类,注入进来。
     private UserDao userDao;
        ...
}

4. xml和注解混合使用

在项目里面,使用xml和注解来完成Spring 的配置。

xml : 负责完成IOC (对象的创建)

注解 : 负责完成DI (属性的注入)

xml托管类
<context:component-scan base-package="com.pri"/>
<bean id="ud" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<bean id="us" class="com.itheima.service.impl.UserServiceImpl"></bean>
注解完成注入:
 public class UserServiceImpl implements UserService {
     @Resource(name="ud")
     private UserDao userDao;
 }

三、Spring测试

  1. 导入jar包

    spring-test-xxx.jar

  2. 托管业务逻辑类,不管是用xml还是注解都可以
  3. <bean id="us" class="com.itheima.service.impl.UserServiceImpl"></bean>
  1. 在测试类上打上注解 ,给测试类的成员变量注入值
//spring扩展了junit的运行环境,除了有测试功能之外,还在里面定义了创建工厂的代码
@RunWith(SpringJUnit4ClassRunner.class)
?
//告诉spring的测试环境,配置文件在哪里
@ContextConfiguration("classpath:applicationContext.xml")
public class TestUserService {

    //测试类里面出现的注解,不用打开扫描开关。因为这个测试环境里面,它会解析这个测试类的注解。
    @Autowired
    private UserService userService;
    @Test
    public void testSave(){
        userService.save();
    }
}

四、AOP

1. 什么是AOP , 它有什么用?

AOP(Aspect Oriented Programming,面向切面编程),可以说是OOP(Object Oriented Programing,面向对象编程)的补充和完善。OOP更多的是侧重于上下间的关系(继承关系 、实现关系) , OOP很难体现左右间的关系。 核心: 在不改动源码的前提下,对原有功能能完成扩展 | 升级

  

2. AOP的底层原理

aop不改源码,但是能够扩展和升级代码。 能够做成这个事情,只有三种解决手法 : 装饰者模式静态代理动态代理 。 AOP 选择的是动态代理 , 装饰者模式和静态代理,要求我们必须写出来装饰类和代理类。 动态代理的实现机制,有两种: 基于JDK的动态搭理基于Cglib的动态代理

1. 动态代理的实现机制

  • 基于JDK的动态代理

如果哪一个真实类有实现接口,那么就采用这种方式,创建出来接口的另一个实现类作为代理类

//jdk动态代理
@Test
public void testJDKPorxy(){

    //UserService userService = new UserServiceImpl();
    //userService.save();

    //1. 先创建真实对象
    final UserService userService = new UserServiceImpl();

    //2. 创建代理对象
    UserService proxyObj = (UserService) Proxy.newProxyInstance(
            userService.getClass().getClassLoader(),  //类加载器,真实类用什么,代理类就用什么
            userService.getClass().getInterfaces(),  //真实类实现什么接口,代理类也实现什么接口
            new InvocationHandler() {//回调函数

                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("invoke~");
                    //userService.save();

                    if(method.getName().equals("save")){
                        Logger.log();
                    }

                    //以不变应万变。 反射调用
                    return method.invoke(userService, args);
                }
            }); 

    //3. 让代理对象干活
    proxyObj.save();  //代理对象。save()  ----> 真实对象.save();
}
  • 基于Cglib动态代理

如果真实类是一个普通类,没有实现接口,那么就采用这种方式, 创建出来真实类的子类作为代理类。

//cglib动态代理
@Test
public void testCglibPorxy(){
    //1. 一定要有真实对象
    final ProductService productService = new ProductService();
    //2. 创建代理
    Enhancer  enhancer = new Enhancer();
    //设置父类是谁
    enhancer.setSuperclass(ProductService.class);
    //设置回调
    enhancer.setCallback(new MethodInterceptor() {
        /*
         * arg0 :代理对象
         * arg3 : 方法的代理
         *
         * 一般这两不用。
         *
         * arg1 : 方法引用
         * arg2 :参数
         */
        @Override
        public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
            Logger.log();
            return arg1.invoke(productService, arg2);
        }
    });

    //创建代理对象
    ProductService proxyObj = (ProductService) enhancer.create();
    proxyObj.save();
}

3. AOP术语

4.AOP的入门

Spring的AOP其实已经准备好了创建代理的代码。只是不知道的是要创建谁的代码。哪些方法需要被增强。我们需要通过配置的形式告诉spring。

  1. 定义业务逻辑类
public class UserServiceImpl implements UserService {
?
    @Override
    public void save() {
        System.out.println("调用了UserServiceImpl 的 save方法");
    }
}
  1. 定义增强类
public class Logger {
    public static void log(){
        System.out.println("输出日志了~~");
    }
}
  1. 导入jar包
    a. 导入 spring必须的jar?    b. 额外导入: ?        spring-aop-xx.jar,spring-aspect-xx.jar?        面向切面过程中,Spring AOP是遵循了AOP联盟的规范实现的,所以需要有AOP联盟的接口包        aopalliance-x.x.jar,接口包依赖aspectjweaver-x.x.x.jar
  1. xml中配置

要导入aop的约束

让spring托管 业务逻辑类 和 增强类
<bean id="us" class="com.itheima.service.impl.UserServiceImpl" ></bean>
<bean id="logger" class="com.itheima.util.Logger" ></bean>?
配置AOP
<!-- 2. 开始配置aop -->
    <aop:config>
        <!-- 配置切入点  expression 表达式 ‘
            execution(* com.xyz.myapp.service.*.*(..))
            execution 固定写法
            第一个* 代表任意返回值
            com.xyz.myapp.service : 包名
            第二个* 包下的任意类
            第三个* 类中的任意方法
            (..) : 任意参数
        saveUser
        saveOrder
        -->
        <aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="aa"/>
        <!-- 配置增强
            根据aa的表达式找到的方法,都给他们做前置增强,增强的功能是log方法
        -->
        <aop:aspect ref="logger">
            <aop:before method="log" pointcut-ref="aa"/>
        </aop:aspect>
    </aop:config>

5. AOP 增强

<aop:config><aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="pointcut01"/>
    <!-- 以后去企业写代码,真正用aop来扩展一个功能,比较少。 除非是我们想扩展第三方jar包。
        aop的思想无处不在:  struts 拦截器 (就是AOP) -->

        <!-- 配置切面aspect -->
        <aop:aspect ref="logger">
            <!-- 前置增强 -->
            <!-- <aop:before method="log" pointcut-ref="pointcut01"/> -->

            <!-- 最终增强 -->
            <!-- <aop:after method="log" pointcut-ref="pointcut01"/> -->

            <!-- 后置增强 -->
            <!-- <aop:after-returning method="log" pointcut-ref="pointcut01"/> -->

            <!-- 异常增强 -->
            <!-- <aop:after-throwing method="log" pointcut-ref="pointcut01"/> -->

            <!-- 环绕增强 -->
            <!-- <aop:around method="around" pointcut-ref="pointcut01"/>  -->
            <aop:before method="log" pointcut-ref="pointcut01"/>
            <aop:after-returning method="log" pointcut-ref="pointcut01"/>
        </aop:aspect>
   </aop:config>
 

原文地址:https://www.cnblogs.com/gdwkong/p/8453162.html

时间: 2024-11-03 00:08:32

Spring入门(二)— IOC注解、Spring测试AOP入门的相关文章

Spring第二天——IOC注解操作与AOP概念

大致内容 spring的bean管理(注解实现) AOP原理 log4j介绍 spring整合web项目的演示 一.spring注解实现bean管理 注解: 代码中一些特殊的标记,使用注解也可以完成一些相关的功能(写法"@") 方法上.类上(详见基础加强) 使用注解创建对象,注入属性(完成day01相似的功能) 可以使用注解,但不可能完全替代xml配置文件 准备工作: 导入包:除了day01的6个核心jar包(当然包括日志的包) 再加上aop的那个jar包(注解功能在里面),也就是图中

使用Spring的注解方式实现AOP入门

首先在Eclipse中新建一个普通的Java Project,名称为springAOP.为了使用Spring的注解方式进行面向切面编程,需要在springAOP项目中加入与AOP相关的jar包,spring aop需要额外的jar包有: com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar spring-aop-4.2.5.RELEASE.jar sprin

Spring顾问、IOC注解和注解增强

一.顾问 通知的一种表现方式(顾问包装通知/增强) Advisor: 名称匹配方法: NameMecthMethodPointcutAdvisor 1.定义了一个业务类 package cn.spring.advisor; /** * 业务接口 */ public interface IService { //业务方法 public void doSome(); public void say(); } 2.定义里一个增强类,实现了增强接口 package cn.spring.advisor;

Spring基础、IOC(控制反转)、AOP(面向切面编程)、Log4j、注解配置

学习示例代码,包含本篇介绍的Spring常用操作示例和所有所需jar文件下载地址:http://download.csdn.net/detail/daijin888888/9556697 1.什么是Spring,有什么作用 --Spring框架属于一个解决方案框架,可以对其他技术和框架进行整合应用. --*好处是:将程序中的各个组件和框架技术进行解耦,便于日后系统维护,升级和扩展操作. --在SSH中,会将Action,DAO组件都交给Spring框架管理,由Spring框架创建这些对象,建立这

spring入门(二) 使用注解代替xml配置

1.导包(略) 2.applicationContext.xml如下: 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:cont

spring学习3_通过注解简单实现AOP

在上一篇中通过XML配置演示了Spring实际进行AOP的过程,这里简单介绍一下通过注解实现这一功能的过程. 1.Spring配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-ins

spring 技术(二) ----- IOC

spring 技术 ---  控制反转(IOC)  也叫依赖注入(DI) (1)基于setter方法的注入 (2)基于构造函数的注入 (3)Bean之间的引用 1. 新建一个Java Project.名为springtest2.然后新建一个package.名为com.gxcme.springtest2. 2. 加入spring框架. 3.新建一个Interface.名为helloInterface.java. 4.新建一个class.名为helloImpl.java.继承helloInterfa

spring学习二:根据spring原理自己写个spring

请先看我另一篇文章:"Spring学习一:IOC(控制反转)和AOP(面向切面)的xml配置和注解方式"中大概知道他的简单用法 那我自己想写一个简单sping,注解的方式以后再写 方式:1.解析xml配置 2.使用java的反射机制生产动态代理对象 3.扫描类上的注解,再用反射(没写) 代码如下(简单实现,重原理轻代码,不喜勿喷) xml配置我就直接用我上一篇spring-test的配置了,代码也用上一篇的,但解析的时候是用自己写的,没有用调用任何spring API代码 <?x

Spring Boot2(二):使用Spring Boot2集成Mybatis缓存机制

前言 学习SpringBoot集成Mybatis的第二章,了解到Mybatis自带的缓存机制,在部署的时候踩过了一些坑.在此记录和分享一下Mybatis的缓存作用. 本文章的源码再文章末尾 什么是查询缓存 MyBatis有一级缓存和二级缓存.记录可以看下这篇博文: 一级缓存 首先看一下什么是一级缓存,一级缓存是指SqlSession.一级缓存的作用域是一个SqlSession.Mybatis默认开启一级缓存. 在同一个SqlSession中,执行相同的查询SQL,第一次会去查询数据库,并写到缓存