SSH框架之旅-spring(2)

spring.jpg

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


1.1 使用注解创建对象

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

示例代码如下:

实体类

加上注解,@Component(value="student") 注解就相当于之前用配置 <bean id="student" class="..."/>

创建对象有四个注解,另外三个注解 @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

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

<?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/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">
  
  <!-- 开启注解扫描 -->
  <context:component-scan base-package="cc.wenshixin"></context:component-scan>
</beans>

测试方法

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 定义 <bean id="" class=""/> @Component,@Respository,@Service,@Controller
bean 名称 通过id或者name指定 @Component("student"),单个value值,value可以省略
bean 注入 <property>或者通过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();
    }
}

配置文件

<?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/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">
  <!-- 配置对象 -->
  <bean id="service" class="cc.wenshixin.service.Service"></bean>
  <bean id="teacherDao" class="cc.wenshixin.dao.TeacherDao"></bean>
  <bean id="studentDao" class="cc.wenshixin.dao.StudentDao"></bean>
  
  <!-- 开启注解扫描 -->
  <context:component-scan base-package="cc.wenshixin"></context:component-scan>
</beans>

测试方法

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 的底层原理

纵向抽取机制

传统方式.png

横向抽取机制

有接口.png
无接口.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(* *.*(..))

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

<?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:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  <!-- 1.配置对象 -->
  <bean id="student" class="cc.wenshixin.entity.Student"></bean>
  <bean id="strengthStudent" class="cc.wenshixin.entity.StrengthStudent"></bean>
  <!-- 2.配置 AOP 操作 -->
  <aop:config>
    <!-- 2.1 配置切入点 -->
    <aop:pointcut expression="execution(* cc.wenshixin.entity.Student.*(..))" id="pointCut"/>
    <!-- 2.2 配置切面把增强用到方法上面 -->
    <aop:aspect ref="strengthStudent">
      <aop:before method="beforeStudy" pointcut-ref="pointCut"/>
      <aop:after-returning method="afterStudy" pointcut-ref="pointCut"/>
      <aop:around method="aroundStudy" pointcut-ref="pointCut"/>
    </aop:aspect>
  </aop:config>
</beans>

测试方法

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("方法之后。。。");
    }
}

配置文件

<?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:aop="http://www.springframework.org/schema/aop" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  <!-- 1.配置对象 -->
  <bean id="student" class="cc.wenshixin.entity.Student"></bean>
  <bean id="strengthStudent" class="cc.wenshixin.entity.StrengthStudent"></bean>
  <!-- 2.开启AOP操作 -->
  <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

测试方法同上

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容