SSH框架之旅-spring(2)

spring.jpg

1.Spring 中的 bean 管理(注解方式)


1.1 使用注解创建对象

Spring 创建对象可以使用配置 xml 文件的方式,也可以使用注解来创建对象,更加的简单。这就需要另外引入一个 spring-aop 的 jar 包,还要在配置文件中加上相对应的约束。

示例代码如下:

实体类

加上注解,@Component(value="student") 注解就相当于之前用配置

创建对象有四个注解,另外三个注解 @controller@Service@Repository 都是 @Component 的衍生注解,它们在功能上是一样的,都是创建对象。从名称上也可以看出注解有划分要标注的类的用途,@Component 用于一般的实体类,@controller 用于 Web 层,@Service 用于 业务逻辑层,@Repository 用于数据持久层。

另外,创建对象是单实例还是多实例也是可以使用注解,只需要在类上加上 @Scope(value="prototype") 就可以创建多实例的对象。

    package cc.wenshixin.entity;
    
    import org.springframework.stereotype.Component;
    
    @Component(value="student")
    public class Student {
        public void study(){
            System.out.println("学习中。。。");
        }
    }

配置文件

在约束配置要加上 xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

开启注解扫描,可以到包中扫描类、方法、属性上是否有注解。



  
  
  

测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.entity.Student;

public class Test1 {
    
    @Test
    public void test01()
    {
        //1.加载spring的配置文件,根据配置文件来创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到通过注解创建的对象
        Student s = (Student) context.getBean("student");
        s.study();
    }
    
}

1.2 使用注解注入属性

创建 service 类和创建 dao 类,在 service 中得到 dao 类的对象。

dao 类

    package cc.wenshixin.dao;
    
    import org.springframework.stereotype.Repository;
    
    @Repository(value="dao")
    public class Dao {
        public void insert()
        {
            System.out.println("插入数据。。。");
        }
    }

service 类

使用注解方式来注入属性,有两种方式,并且两种方式都不要需要在 dao 中添加 set 方法。

package cc.wenshixin.service;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cc.wenshixin.dao.Dao;

@Service(value="service")
public class StudentService {
    //第一种方式
    /*@Autowired
    private Dao dao;*/

    //第二种方式
    //name属性值写创建 dao 对象时注解中的 value 值
    @Resource(name="dao")
    private Dao dao;
    
    public void add()
    {
        System.out.println("添加操作。。。");
        dao.insert();
    }
}

测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.entity.Student;
import cc.wenshixin.service.StudentService;

public class Test1 {
    
    @Test
    public void test01()
    {
        //1.加载spring的配置文件,根据配置文件来创建对象
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到通过注解创建的对象
        StudentService service = (StudentService) context.getBean("service");
        service.add();
    }
}

1.3 配置方式和注解方式的混合使用

在开发中,经常 xml 配置文件方式和注解方式混合使用,创建对象使用配置文件,而属性注入使用注解方式。xml 配置方式结构清晰,注解方式方便属性注入。

Spring 中 bean 管理方式的比较

xml配置 注解配置
bean 定义 @Component,@Respository,@Service,@Controller
bean 名称 通过id或者name指定 @Component("student"),单个value值,value可以省略
bean 注入 或者通过p命名空间 @Autowired 按类型注入,@Resource(name="")

示例代码如下:

dao 类

package cc.wenshixin.dao;

public class TeacherDao {
    public void insert()
    {
        System.out.println("添加老师。。。");
    }
}
package cc.wenshixin.dao;

public class StudentDao {
    public void insert()
    {
        System.out.println("添加学生。。。");
    }
}

service 类

package cc.wenshixin.service;

import javax.annotation.Resource;
import cc.wenshixin.dao.StudentDao;
import cc.wenshixin.dao.TeacherDao;

public class Service {
    @Resource(name="teacherDao")
    private TeacherDao teacherDao;
    @Resource(name="studentDao")
    private StudentDao studentDao;
    
    public void add()
    {
        System.out.println("添加操作。。。");
        teacherDao.insert();
        studentDao.insert();
    }
}

配置文件



  
  
  
  
  
  
  

测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.service.Service;

public class Test1 {
    @Test
    public void test()
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Service service = (Service) context.getBean("service");
        service.add();
    }
}

2.Spring 中的 AOP


2.1 AOP 完整概述

AOP,全名 Aspect Oriented Programming,面向切面编程,在 Struts2 的拦截器中已经提到过 AOP,时通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,扩展功能而不修改源代码,如:权限校验、日志记录、性能监控、事务控制。AOP采取横向抽取机制,取代了传统纵向继承体系的重复代码。AOP 解决 OOP(面向对象编程) 中遇到的一些问题,是 OOP 的延续和扩展。

底层的动态代理机制有两种:

    1. 有接口,JDK的动态代理,针对实现接口的类产生代理,生成接口实现类对象。
    1. 没有接口,Cglib的动态代理,应用的是底层的字节码增强技术,生成当前类的子类对象。

2.2 AOP 的底层原理

纵向抽取机制

SSH框架之旅-spring(2)_第1张图片
传统方式.png

横向抽取机制

SSH框架之旅-spring(2)_第2张图片
有接口.png
SSH框架之旅-spring(2)_第3张图片
无接口.png

2.3 AOP 操作的相关术语

  • Joinpoint(连接点):类里面可以被增强的方法,这些方法就称为是连接点。
  • Pointcut(切入点):切入点是指要对连接点进行拦截。在一个类里面可以有很多的方法被增强,比如实际操作中,只是增强了类里面的 add 方法和 update 方法,实际增强的方法就称为是切入点。
  • Advice(通知/增强):通知是指拦截到 Joinpoint 之后要做的事情就是通知,通知又分为前置通知、后置通知、异常通知,最终通知、环绕通知(切面要完成的功能)。要增强的逻辑功能称为是增强,比如扩展日志功能,这个日志功能就成为是通知或者是增强。前置通知:在增强的方法之前执行;后置通知:在增强的方法之后执行;异常通知:方法出现异常时;最终通知:在后置之后执行;环绕通知:在方法之前和之后执行。
  • Aspect(切面):切入点和通知(引介)的结合。把增强应用到具体方法上面的过程称为切面。把增强用到切入点过程。
  • Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction 可以在运行期为类动态地添加一些方法或 Field。
  • Target(目标对象):代理的目标对象(要增强的类)。
  • Weaving(织入):是把增强应用到目标的过程,也即是把 advice 应用到 target 的过程。
  • Proxy(代理):一个类被 AOP 织入增强后就产生一个结果代理类。

2.4 AOP 的实际操作

在 Spring 中进行 AOP 操作使用 Aspectj 实现的,Aspectj 不是 Spring 的一部分,和 Spring 一起使用 AOP 操作。
使用 Aspectj 实现 AOP 也有两种方式:

  • 1.基于 Aspectj 的xml配置
  • 2.基于 Aspectj 的注解方式

除了上面的 jar 包之外,还需要导入 Aspectj 的相关 jar 包 Aspectjweaver.jar 下载地址,aopalliance.jar,这个在 Struts2 的lib中有,spring-aop.jarspring-aspects.jar

2.4.1 配置文件方式

实体类

package cc.wenshixin.entity;

public class Student {
    public void study()
    {
        System.out.println("学习中。。。");
    }
}

增强类

package cc.wenshixin.entity;

import org.aspectj.lang.ProceedingJoinPoint;

public class StrengthStudent {
    public void beforeStudy()
    {
        System.out.println("前置增强。。。");
    }
    
    public void afterStudy()
    {
        System.out.println("后置增强。。。");
    }
    
    //环绕通知
    public void aroundStudy(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        //方法之前执行
        System.out.println("方法之前。。。");
        //执行被增强的方法
        proceedingJoinPoint.proceed();
        //方法之后执行
        System.out.println("方法之后。。。");
    }
}

配置文件

aspectj配置常用的表达式
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)

  • 1.execution(* cc.wenshixin.entity.Student.add(..))
  • 2.execution(* cc.wenshixin.entity.Student.*(..))
  • 3.execution(* *.*(..))

注意:第一个和后面的路径有一个空格,后面的括号中是两个点,不是三个点*



  
  
  
  
  
    
    
    
    
      
      
      
    
  


测试方法

package cc.wenshixin.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cc.wenshixin.entity.Student;

public class Test1 {
    @Test
    public void test()
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        Student s = (Student) context.getBean("student");
        s.study();
    }
}

2.4.2 注解方式

实体类同上

增强类
Aspectj 的 AOP 注解

  • @Aspect:定义切面增强类的注解
  • 通知(增强)类型
    • @Before:前置通知
    • @AfterReturing:后置通知
    • @Around:环绕通知
    • @AfterThrowing:异常抛出通知
package cc.wenshixin.entity;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class StrengthStudent {
    @Before(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void beforeStudy()
    {
        System.out.println("前置增强。。。");
    }
    @After(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void afterStudy()
    {
        System.out.println("后置增强。。。");
    }
    
    //环绕通知
    @Around(value="execution(* cc.wenshixin.entity.Student.*(..))")
    public void aroundStudy(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
    {
        //方法之前执行
        System.out.println("方法之前。。。");
        //执行被增强的方法
        proceedingJoinPoint.proceed();
        //方法之后执行
        System.out.println("方法之后。。。");
    }
}

配置文件



  
  
  
  
  


测试方法同上

3. 其他概念


3.1 log4j 的介绍

log4j 是一个日志包,通过 log4j 可以看到程序运行过程中更详细的信息,查看日志。使用时需要导入 log4j 的 jar 包,下载位置,并复制 log4j 的配置文件 log4j.properties 到 src 目录。

log4j.properties文件中的内容

log4j.rootLogger 用来设置日志的级别,info可以看到基本信息,debug可以看到更详细的信息。

#
# Log4J Settings for log4j 1.2.x (via jakarta-commons-logging)
#
# The five logging levels used by Log are (in order):
#
#   1. DEBUG (the least serious)
#   2. INFO
#   3. WARN
#   4. ERROR
#   5. FATAL (the most serious)


# Set root logger level to WARN and append to stdout
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%d %5p (%c:%L) - %m%n

你可能感兴趣的:(SSH框架之旅-spring(2))