Spring 框架概述
Spring 框架是一个轻量级的解决方案,并且是构建企业就绪应用程序的一站式潜在 Store。但是Spring 是模块化的,允许您仅使用所需的那些 Component,而不必引入其他 Component。您可以将 IoC 容器与顶部的任何 Web 框架一起使用,但也可以仅使用Hibernate 集成代码或JDBC 抽象层。 Spring 框架支持声明式事务 Management,通过 RMI 或 Web 服务对逻辑的远程访问以及用于持久化数据的各种选项。它提供了功能齐全的MVC framework,并使您能够将AOP透明地集成到软件中。
Spring 被设计为非侵入式的,这意味着您的域逻辑代码通常不依赖于框架本身。在集成层(例如数据访问层)中,将存在对数据访问技术和 Spring 库的某些依赖关系。但是,将这些依赖项与其余代码库隔离起来应该很容易。
spring、springmvc、springboot关系
spring mvc < spring <springboot
spring boot就是一个大框架里面包含了许许多多的东西,其中spring就是最核心的内容之一,当然就包含spring mvc
spring mvc 是只是spring 处理web层请求的一个模块
创始人
Rod Johnson
地位
java应用程序框架中的No.1,目前无人撼动,且存在时间长,影响深远。
优点
(1)方便解耦,简化开发
Spring就是一个大工厂,可以将所有对象创建和依赖的关系维护,交给Spring管理。
(2)AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
(3)声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程。
(4)方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序。
(5)方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架的直接支持(如:Struts、Hibernate、MyBatis等)。
(6)降低JavaEE API的使用难度
Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
简单了解工厂模式
控制反转实现原理
public class Person { public int id; } public class Student extends Person { public int num; } public class Person { public int id; } public class Factory { private final static String STUDENT="student"; private final static String TEACHER="teacher"; public Person getPerson(String str) { if(str.equals(STUDENT)) { return new Student(); }else if(str.equals(TEACHER)) { return new Teacher(); }else { return null; } } } class Test1 { @Test void test() { Factory factory = new Factory(); Student student =(Student) factory.getPerson("student"); System.out.println(student.toString()); } }
spring框架中不需要new我们的工厂类。由容器去做
简单了解下JUnit4
JUnit4是一个易学易用的Java单元测试框架,使用非常广泛
引用
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
演示
public class AppTest { private User user; @Before public void init() { user = new User(); user.setId(1); user.setUsername("yitian"); user.setPassword("1234"); user.setBirthday(LocalDate.now()); } @Test public void testBean() { Assert.assertNotNull(user); } }
要让一个方法变成测试方法,只需要向其添加@Test注解即可。在测试方法中我们可以使用传统的System.out.println方法来输出,也可以使用各种日志框架来打印日志。还可以使用几个注解来初始化和清理测试方法用到的数据。Before和After注解会在每个测试方法之前和之后调用。
体系
核心容器(Core Container)
Core和Beans模块提供了Spring最基础的功能,提供IOC和依赖注入特性。这里的基础概念是BeanFactory,它提供对Factory模式的经典实现来消除对程序性单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
Context模块基于Core和Bean来构建,它提供了用一种框架风格地方式来访问对象,有些像JNDI注册表。Context封装包继承了beans包的功能,还增加了国际化(I18N),事件传播,资源装载,以及透明创建上下文,例如通过servlet容器,以及对大量JavaEE特性的支持,如EJB,JMX.核心接口是ApplicationContext.
Expression Language,表达式语言模块,提供了在运行期间查询和操作对象图的强大能力。支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从spring容器获取Bean,它也支持列表投影、选择和一般的列表聚合等。
数据访问/集成部分(Data Access/Integration)
JDBC模块,提供对JDBC的抽象,它可消除冗长的JDBC编码和解析数据库厂商特有的错误代码。
ORM模块,提供了常用的“对象/关系”映射API的集成层。其中包括JPA、JDO、Hibernate和iBatis.利用ORM封装包,可以混合使用所有Spring提供的特性进行“对象/关系”映射,如简单声明式事务管理。
OXM模块,提供一个支持Object和XML进行映射的抽象层。其中包括JAXB、Castor、XMLBeans、JiBX和XStream.
JMS模块,提供一套“消息生产者、消费者”模板用于更加简单的使用JMS,JMS用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
Transaction模块,支持程序通过简单声明式事务管理,只要是Spring管理对象都能得到Spring管理事务的好处,即使是POJO,也可以为他们提供事务。
web
web-socket模块,websocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,spring支持websocket通信。
web模块,提供了基础的web功能。例如多文件上传、集成IOC容器、远程过程访问以及对webservice支持,并提供一个RestTemplate类来提供方便的Restful services访问。
web-servlet模块,提供了web应用的model-view-controller(MVC)实现。spring mvc框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的JSP标签,完全无缝与spring其他技术协作。
web-portlet模块,提供了在portlet环境下的mvc实现
aop
提供了符合aop联盟规范的面向切面的编程实现,让你可以定义如方法拦截器和切入点,从逻辑上讲,可以减弱代码的功能耦合,清晰地被分离开。而且,利用源码级地元数据功能,还可以将各种行为信息合并到你的代码中。
aspects
提供了与AspectJ的集成功能,AspectJ是一个功能强大且成熟的AOP框架
Instrumentation
提供一些类级的工具支持和ClassLoader级的实现,可以在一些特定的应用服务器中使用。
messaging
该模块提供了对消息传递体系结构和协议的支持。
Test
支持使用JUnit等Spring组件进行单元测试和集成测试。
相关jar作用
org.springframework spring-aop ——Spring的面向切面编程,提供AOP(面向切面编程)实现 org.springframework spring-aspects —— Spring提供对AspectJ框架的整合 org.springframework spring-beans —— SpringIoC(依赖注入)的基础实现 org.springframework spring-context —— Spring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等 org.springframework spring-context-support —— Spring-context的扩展支持,用于MVC方面 org.springframework spring-core —— Spring的核心组件 org.springframework spring-expression —— Spring表达式语言 org.springframework spring-instrument —— Spring对服务器的代理接口 org.springframework spring-instrument-tomcat —— Spring对Tomcat的连接池的集成 org.springframework spring-jdbc —— JDBC支持包,包括数据源设置和JDBC访问支持 org.springframework spring-jms —— JMS支持包,包括辅助类来发送和接收JMS消息 org.springframework spring-messaging —— 信息体系结构和协议的支持 org.springframework spring-orm —— 对象/关系映射,整合第三方的ORM框架,如hibernate,ibatis,jdo,以及spring的JPA实现 org.springframework spring-oxm —— 对象的XML映射,可以让Java与XML之间来回切换 org.springframework spring-test —— 对于单元测试和集成测试的简单封装 org.springframework spring-tx —— 为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理 org.springframework spring-web —— SpringMVC支持WEB端应用部署架构 org.springframework spring-webmvc —— REST Web服务和Web应用的视图控制器的实现 org.springframework spring-webmvc-portlet —— SpringMVC的增强–MVC的实现作为一个Portlet的环境 org.springframework spring-websocket —— sockjs WebSocket的实现,包括对 STOMP的支持
Spring依赖包的描述: aopalliance.jar —— AOP联盟的API包,里面包含了针对面向切面的接口。通常Spring等其它具备动态织入功能的框架依赖此包。 aspectjweaver-1.5.0.jar —— 用于在Spring 中集成AspectJ AspectJ LTW织入器 cglib-3.1.jar —— cglib代理 实现AOP的一种方式 commons-collections-3.2.2.jar —— Apache Commons包中的一个,包含了一些Apache开发的集合类,功能比java.util.*强大。 commons-dbcp-1.2.1.jar —— DBCP数据库连接池 commons-logging-1.1.1.jar —— Apache Commons包中的一个,包含了日志功能 commons-pool-1.6.jar —— DBCP是一个依赖commons-pool对象池机制的数据库连接池 standard.jar —— JSP 标准标签库,和jstl.jar 一起使用,jstl-1.2.jar 不在需要。
入门
1.了解XML Schema
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:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd "> </beans>
其实还有很多,如果你用不到你就可以不要去配 建议把版本号删了 比如以下这种
http://www.springframework.org/schema/beans/spring-beans.xsd
3.配置spring-bean.xml
新建maven项目
pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>s309</groupId> <artifactId>springdem</artifactId> <version>1.0-SNAPSHOT</version> <name>springdem</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> <spring.version>4.1.6.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <build> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle --> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-jar-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle --> <plugin> <artifactId>maven-site-plugin</artifactId> <version>3.7.1</version> </plugin> <plugin> <artifactId>maven-project-info-reports-plugin</artifactId> <version>3.0.0</version> </plugin> </plugins> </pluginManagement> </build> </project>
bean xml文件
<?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="stu" class="dasd.pojo.Student"> <property name="id" value="1"> </property> <property name="name" value="afeng"> </property> </bean> </beans> JavaBeans 是 Java 中一种特殊的类,可以将多个对象封装到一个对象(bean)中,特点是可序列化,提供无参构造器,提供 getter 方法和 setter 方法访问对象的属性。
4.实例化容器获取bean
public class App { @Test public void showBean(){ ApplicationContext context = new ClassPathXmlApplicationContext("spring-bean.xml"); Student stu = (Student)context.getBean("stu"); System.out.println(stu); } }
5.bean生命周期
Spring Bean 的生命周期在整个 Spring 中占有很重要的位置,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Singleton模式产生单一实例,在spring中,singleton属性默认是true,只有设定为false,则每次指定别名取得的Bean时都会产生一个新的实例,Spring只帮我们管理单例模式Bean的完整生命周期,对于prototype的bean,Spring在创建好交给使用者之后则不会再管理后续的生命周期。
在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例化,然后该bean就可以使用了。一旦该bean不再被使用,则由Java自动进行垃圾回收
1、实例化一个Bean 2、按照Spring上下文对实例化的Bean进行配置,也就是IOC注入 3、如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String)方法,传递的参数就是Spring配置文件中Bean的id值
4、如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(BeanFactory),传递的是Spring工厂自身
5、如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文
6、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法, BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用那个的方法,也可以被应用于内存或缓存技术;
7、如果Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法。 8、如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法 9、当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用那个其实现的destroy()方法;
10、最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
6.再说几句
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"中xsi的意思是 : 本xml文件中要用到某些来自xsi代表的“http://www.w3.org/2001/XMLSchema-instance”这个命名空间的元素 比如用来引入无命名空间schema文件的noNamespaceSchemaLocation="XXX"; 以及引入自带命名空间的schema文件的schemaLocation="XXX"这些元素。 这些元素是包含在xsi命名空间中的,所有的xml文件只要引用这些元素 就要引入xsi这个命名空间。 xsi这三个字母不是硬性规定,只是大家都这么用,方便阅读而已。
xsi是http://www.w3.org/2001/XMLSchema-instance的别名。 这样用于下面元素的时候可以这样<xsi:element />而不用带上长长的uri。 有了命名空间以后,在同一级元素就可以使用同一个元素名称而不会混乱: <xsi1:element /> <xsi2:element />
在实例中引用模式文档
XML Schema提供了两个在实例文档中使用的特殊属性,用于指出模式文档的位置。这两个属性是:xsi:schemaLocation和xsi:noNamespaceSchemaLocation,前者用于声明了目标名称空间的模式文档,后者用于没有目标名称空间的模式文档,它们通常在实例文档中使用。
4.5.7.1 xsi:schemaLocation属性
xsi:schemaLocation属性的值由一个URI引用对组成,两个URI之间以空白符分隔。第一个URI是名称空间的名字,第二个URI给出模式文档的位置,模式处理器将从这个位置读取模式文档,该模式文档的目标名称空间必须与第一个URI相匹配。
beans标签
属性
属性名 | 作用 |
---|---|
default-autowire-candidates | 是否接受被自动装配,如果是false,那么beans标签下的所有子bean都不接受被自动装配。默认是true。 |
default-destroy-method | 指定销毁方法。正常情况下,如果bean都有自己的销毁方法,那么要声明多次,如果在beans标签中声明了此属性,假如方法为 hehe(),那么每个子bean只需要直接实现各自的hehe()方法即可,即完成销毁代码编写。如果子bean自己用destroy-method指定了自己的销毁方法,那么就是自己的,不用beans的default-destroy-method。 |
default-init-method | 指定初始化方法。和销毁方法同理。 |
default-lazy-init | 是否延迟初始化。如果设置为true(要延迟),那么所有的子bean都要延迟。如果此时有子bean自己设置了lazy-init为false,那么自己的lazy-init优先生效。节约项目启动时间 |
profile | 指定一类bean配置。项目的开发分开发、测试、生产,三个阶段的项目配置肯定略有不同,一般我们手动地去修改配置,完了再部署,可是很不方便,可能没修改完或修改正确,那么此时如果我们事先把三种配置分别用三个文件写好,然后每次将profile指定其中一个文件启动项目,那不就方便多了。profile就是这个功能。测试类要加上@ActiveProfiles("xxx")要是在tomcat上就要在webxml里去配置了 |
default-autowire | 自动装配模式。若子bean没有设置自己的autowire,那么就用beans。自动装配机制慎用,它屏蔽了装配细节,容易产生潜在的错误;byType与byName 区别:byName 如果有其他的bean的id是和其属性名一致,就自动注入 byType就是类型一致就注入 而且如果有两个就报错 |
常用子标签
spring整合junit测试(看清楚包再导入)
package dasd; import dasd.pojo.Student; import dasd.service.StudentService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; /** * Hello world! * */ @ContextConfiguration("classpath:spring-bean.xml") @RunWith(SpringJUnit4ClassRunner.class) public class App { @Autowired StudentService studentService; @Test public void doSome(){ studentService.syo(); } }
注意点
@RunWith 用于指定junit运行环境,是junit提供给其他框架测试环境接口扩展,为了便于使用spring的依赖注spring提供了org.springframework.test.context.junit4.SpringJUnit4ClassRunner作为Junit测试环境
@ContextConfiguration导入配置文件
如果有多个配置文件
@ContextConfiguration(locations = { classpath:spring-bean1.xml", "classpath:spring-bean2.xml" })
控制反转(Inversion of Control---IOC)
是一种设计思想,人话:将对象交给容器容器去管理,例如不需要你去new象了,由容器去创建对象提供给你。
依赖注入(Dependency Injection---DI)
就是你写的类在运行的时候依赖于ioc容器在你需要某个对象的时候给你去注入对象
面向切面(Aspect Oriented Programming---AOP)
面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
主要用作于
日志记录,性能统计,安全控制,事务处理,异常处理等等。
bean标签
属性 | 描述 |
---|---|
id | id标签是bean的唯一标识,IoC容器中bean的id标签不能重复,否则报错。 |
name | 名称标识,我告诉你别重复,但是一个bean标签可以起多个name 用,隔开 |
class | 全类名 |
factory-method | 设置了factory-method属性后,将指定创建bean的工厂方法 一般不用 |
factory-bean | 设置了factory-bean属性后,将指定创建bean的工厂类对象,class属性将失效 一般不用 |
init-method | 它的作用是在创建一个bean之后调用该方法,初始化方法必须是一个无参方法。 |
destory-method | 它的作用是在销毁bean之前可以执行指定的方法。注意:必须满足scope="singleton",并且destroy方法参数个数不能超过1,并且参数类型只能为boolean。 |
scope | bean的作用范围,它包括 singleton:单例,指定该bean在spring容器中只有一个对象,所有通过getBean获得的对象都是同一个对象。 prototype:只要重新获取该bean,都将返回一个不同的对象。 request:在一次http请求中对应一个bean,类似于servlet session:在一次会话中对应一个bean。 |
autowire | autowire default(默认):采用父级标签beans中的default-autowire属性; byName:通过属性名称来自动装配,即A类中的B对象名称为name,那么将根据id="name"找到该bean进行装配,A类必须提供setName方法; byType:根据属性类型来找到和配置文件中配置的class类型一致的bean来自动装配,如果找到多个类型一致的bean,则抛异常,如果一个都没有找到,则不执行装配操作,也不抛出异常。 no:不执行自动装配操作,只能用<ref标签进行装配; constructor:根据构造器中参数类型来自动装配,如果找到多个类型一致的bean,则抛异常,如果一个都没有找到,则不执行装配操作,但是抛出异常(这是和byType不一样的地方)。 “autodetect”(spring3之前有该值,从spring4开始该值被抛弃):通过Bean类的反省机制(introspection)决定是使用“constructor”还是使用“byType”。 |
parent | 指定bean的父类,class属性失效。 |
primary | 当一个bean出现多个候选者时,设置primary="true"后,则优先使用该bean来自动装配。 |
lazy-init | 设置bean对象是否懒加载,如果设为true,则应用第一次用到bean时才实例化对象,否则在初始化spring容器时加载单例bean对象。(非单例不实例化) |
abstract | 设置bean是否为抽象类,默认abstract="false",如果设为true,将不能被实例化; |
id name区别
id属性命名必须满足XML的命名规范,因为id其实是XML中就做了限定的。总结起来就相当于一个Java变量的命名:不能以数字,符号打头,不能有空格
name属性则没有这些限定
bean常用子标签
标签名 | 属性 |
---|---|
property | 自动注入jaabean的成员变量 |
constructor-arg | 构造器参数(顺序注入),此种方式会按照顺序注入构造器的参数 |
四种实例化bean的方式
使用构造器实例化Bean
这是最简单的方式,Spring IoC容器即能使用默认空构造器也能使用有参数构造器两种方式创建Bean,如以下方式指定要创建的Bean类型:
使用空构造器进行定义,使用此种方式,class属性指定的类必须有空构造器
<bean name="people" class="pojo.People"></bean>
使用有参数构造器进行定义,使用此种方式,可以使用< constructor-arg>标签指定构造器参数值,其中index表示位置,value表示常量值,也可以指定引用,指定引用使用ref来引用另一个Bean定义
<bean class="kj08.pojo.Student" id="student" > <constructor-arg index="0" value="1"></constructor-arg> <constructor-arg index="1" value="1"></constructor-arg> <constructor-arg index="2" value="1"></constructor-arg> </bean>
使用静态工厂方式实例化Bean
使用静态工厂方式实例化Bean,使用这种方式除了指定必须的class属性,还要指定factory-method属性来指定实例化Bean的方法,而且使用静态工厂方法也允许指定方法参数,spring IoC容器将调用此属性指定的方法来获取
public class Hello { private String str; public String getstr() { return str; } public void setstr(string str) { this.str = str; } public Hello(String str){ this.str = str; } public Hello() { } public class HelloInstanceFactory{ public static Hello newInstanceHello(String message) { return new Hello(message); } }
<bean id="hello" class="com.nieshenkuan.staticFactory. HelloInstanceFactory" factory-method="newInstanceHello"> <constructor-arg index="0" value="helloworld! "></constructor-arg> </bean>
使用实例工厂方法实例化Bean
使用这种方式不能指定class属性,此时必须使用factory-bean属性来指定工厂Bean,factory-method属性指定实例化Bean的方法,而且使用实例工厂方法允许指定方法参数,方式和使用构造器方式一样。
public class Hello { private String str; public String getstr() { return str; } public void setstr(string str) { this.str = str; } public Hello(String str){ this.str = str; } public Hello() { } public class HelloInstanceFactory1{ public Hello newInstanceHello(String message) { return new Hello(message); } }
<bean id="beanInstanceFactory"class="com.nieshenkuan.staticFactory.HelloInstanceFactory"></bean> <bean id="hello2"factory-bean="beanInstanceFactory"factory-method="newInstanceHello"><constructor-arg index="e" value="Helloworld2!"></constructor-arg></bean>
用 setter 方式
<bean name="people" class="com.nieshenkuan.model. People" id="people"> <property name="name" value="nsk"></property> <property name="age" value="24"></property> </bean>
注入不同数据类型
package kj08.pojo; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; public class TestEntity { private String specialCharacter1; // 特殊字符值1 private String specialCharacter2; // 特殊字符值2 private Student innerBean; // JavaBean类型 private List<String> list; // List类型 private String[] array; // 数组类型 private Set<String> set; // Set类型 private Map<String, String> map; // Map类型 private Properties props; // Properties类型 private String emptyValue; // 注入空字符串值 private String nullValue = "init value"; // 注入null值 public void setSpecialCharacter1(String specialCharacter1) { this.specialCharacter1 = specialCharacter1; } public void setSpecialCharacter2(String specialCharacter2) { this.specialCharacter2 = specialCharacter2; } public void setInnerBean(Student user) { this.innerBean = user; } public void setList(List<String> list) { this.list = list; } public void setArray(String[] array) { this.array = array; } public void setSet(Set<String> set) { this.set = set; } public void setMap(Map<String, String> map) { this.map = map; } public void setProps(Properties props) { this.props = props; } public void setEmptyValue(String emptyValue) { this.emptyValue = emptyValue; } public void setNullValue(String nullValue) { this.nullValue = nullValue; } public void showValue() { System.out.println("特殊字符1:" + this.specialCharacter1); System.out.println("特殊字符2:" + this.specialCharacter2); System.out.println("内部Bean:" + this.innerBean.getStudentName()); System.out.println("List属性:" + this.list); System.out.println("数组属性[0]:" + this.array[0]); System.out.println("Set属性:" + this.set); System.out.println("Map属性:" + this.map); System.out.println("Properties属性:" + this.props); System.out.println("注入空字符串:[" + this.emptyValue + "]"); System.out.println("注入null值:" + this.nullValue); } }
<?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-3.2.xsd"> <bean id="entity" class="entity.TestEntity"> <!-- 使用<![CDATA[]]>标记处理XML特 殊字符 --> <property name="specialCharacter1"> <value><![CDATA[P&G]]></value> </property> <!-- 把XML特殊字符替换为实体引用 --> <property name="specialCharacter2"> <value>P&G</value> </property> <!-- 定义内部Bean --> <property name="innerBean"> <bean class="entity.User"> <property name="username"> <value>Mr. Inner</value> </property> </bean> </property> <!-- 注入List类型 --> <property name="list"> <list> <!-- 定义List中的元素 --> <value>足球</value> <value>篮球</value> </list> </property> <!-- 注入数组类型 --> <property name="array"> <list> <!-- 定义数组中的元素 --> <value>足球</value> <value>篮球</value> </list> </property> <!-- 注入Set类型 --> <property name="set"> <set> <!-- 定义Set或数组中的元素 --> <value>足球</value> <value>篮球</value> </set> </property> <!-- 注入Map类型 --> <property name="map"> <map> <!-- 定义Map中的键值对 --> <entry> <key> <value>football</value> </key> <value>足球</value> </entry> <entry> <key> <value>basketball</value> </key> <value>篮球</value> </entry> </map> </property> <!-- 注入Properties类型 --> <property name="props"> <props> <!-- 定义Properties中的键值对 --> <prop key="football">足球</prop> <prop key="basketball">篮球</prop> </props> </property> <!-- 注入空字符串值 --> <property name="emptyValue"> <value></value> </property> <!-- 注入null值 --> <property name="nullValue"> <null/> </property> </bean> </beans>
利用注解赋值
@value
如果属性简单就用这个,如果复杂就用xml
用这个之前请在配置文件中写上
<context:component-scan base-package="xxx"/>扫描注解
@Autowired 与@Resource区别
1、不同点
(1)@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
(2)@Autowired装配顺序
@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。(通过类型匹配找到多个candidate,在没有@Qualifier、@Primary(@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常。(只对接口的多个实现生效))注解的情况下,会使用对象名作为最后的匹配)
@Autowired装配顺序:
①看类型
②定义的名称
③字段名
(3)@Resource(rui sao si)装配顺序
@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序:
①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
@Resource的作用相当于@Autowired,只不过@Autowired默认按照byType自动注入。
2、共同点
两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
注:最好是将@Resource放在setter方法上,因为这样更符合面向对象的思想,通过set、get去操作属性,而不是直接去操作属性。
AOP
相关概念
-
切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是Java应用程序中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用通过类(基于模式(XML)的风格)或者在普通类中以@Aspect注解(AspectJ风格)来实现。
-
连接点(Join point):程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中一个连接点总是代表一个方法的执行。个人理解:AOP拦截到的方法就是一个连接点。通过声明一个org.aspectj.lang.JoinPoint类型参数我们可以在通知(Advice)中获得连接点的信息。这个在稍后会给出案例。
-
通知(Advice):在切面(Aspect)的某个特定连接点上(Join point)执行的动作。通知的类型包括"around","before","after"等等。通知的类型将在后面进行讨论。许多AOP框架,包括Spring 都是以拦截器作为通知的模型,并维护一个以连接点为中心的拦截器链。总之就是AOP对连接点的处理通过通知来执行。个人理解:Advice指当一个方法被AOP拦截到的时候要执行的代码。
-
切入点(Pointcut):匹配连接点(Join point)的断言。通知(Advice)跟切入点表达式关联,并在与切入点匹配的任何连接点上面运行。切入点表达式如何跟连接点匹配是AOP的核心,Spring默认使用AspectJ作为切入点语法。个人理解:通过切入点的表达式来确定哪些方法要被AOP拦截,之后这些被拦截的方法会执行相对应的Advice代码。
-
引入(Introduction):声明额外的方法或字段。Spring AOP允许你向任何被通知(Advice)对象引入一个新的接口(及其实现类)。个人理解:AOP允许在运行时动态的向代理对象实现新的接口来完成一些额外的功能并且不影响现有对象的功能。
-
目标对象(Target object):被一个或多个切面(Aspect)所通知(Advice)的对象,也称作被通知对象。由于Spring AOP是通过运行时代理实现的,所以这个对象永远是被代理对象。个人理解:所有的对象在AOP中都会生成一个代理类,AOP整个过程都是针对代理类在进行处理。
-
AOP代理(AOP proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能),在Spring中AOP可以是JDK动态代理或者是CGLIB代理。
-
织入(Weaving):把切面(aspect)连接到其他的应用程序类型或者对象上,并创建一个被通知对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯AOP框架一样,在运行时完成织入。通俗:把切面跟对象关联并创建该对象的代理对象的过程。
通知(Advice)的类型
-
前置通知(Before advice):在某个连接点(Join point)之前执行的通知,但这个通知不能阻止连接点的执行(除非它抛出一个异常)。
-
返回后通知(After returning advice):在某个连接点(Join point)正常完成后执行的通知。例如,一个方法没有抛出任何异常正常返回。
-
抛出异常后通知(After throwing advice):在方法抛出异常后执行的通知。
-
后置通知(After(finally)advice):当某个连接点(Join point)退出的时候执行的通知(不论是正常返回还是发生异常退出)。
-
环绕通知(Around advice):包围一个连接点(Join point)的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
execution语法
语法为:execution(修饰符 返回值 包名.类名/接口名.方法名(参数列表))
其中:
1、返回类型、方法名、参数是必须有的.
2、表示任意值. 比如返回类型,方法名等. 3、(..)可以代表所有参数,()代表一个参数,(*,String)代表第一个参数为任何值,第二个参数为String类型.
举例说明: 1、任意公共方法的执行: execution(public * (..)) 2、任何一个以“set”开始的方法的执行: execution( set(..)) 3、AccountService 接口的任意方法的执行: execution( com.xyz.service.AccountService.(..)) 4、定义在service包里的任意方法的执行: execution( com.xyz.service..(..)) 5、定义在service包和所有子包里的任意类的任意方法的执行: execution(* com.xyz.service...(..)) 6、定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行: execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.(..))") 最靠近(..)的为方法名,靠近.(..))的为类名或者接口名
AOP操作两种方式
配置文件方式
<?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" xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd "> <bean name="student1" class="dasd.pojo.Student" > <property name="id" value="1"> </property> <property name="name" value="afeng"> </property> </bean> <bean id="teacher1" class="dasd.pojo.Teacher" > <property name="id" value="1"> </property> <property name="name" value="afeng"> </property> </bean> <bean id="stuAsp" class="dasd.asp.StudentAsp"></bean> <bean id="StudentService" class="dasd.service.impl.StudentService"></bean> <aop:config> <aop:pointcut id="pointcut" expression="execution(public void dasd.service.impl.StudentService.doSome(..)) "></aop:pointcut> <aop:aspect id="stuAsp" ref="stuAsp"> <aop:before method="before" pointcut-ref="pointcut"/> <aop:after-returning method="after" pointcut-ref="pointcut"/> <aop:after-throwing method="throwAfter" pointcut-ref="pointcut"/> <aop:after method="AfterFinally" pointcut-ref="pointcut"/> <aop:around method="around" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans>
package dasd.service; public interface IStudentService { public void doSome(); } package dasd.service.impl; import dasd.service.IStudentService; public class StudentService implements IStudentService { @Override public void doSome() { int i= 1/0; System.out.println(i); } } package dasd; import dasd.pojo.Student; import dasd.service.IStudentService; import dasd.service.impl.StudentService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @ContextConfiguration("classpath:spring-bean.xml") @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles("dev") public class App { @Autowired IStudentService studentService; @Test public void doSome(){ studentService.doSome(); } }
相关标签
标签名 | 作用 | 属性 |
---|---|---|
aop:config | 作用:用于声明开始aop的配置 | |
aop:aspect | 作用:用于配置切面 | id:给切面提供一个唯一标识。 ref:引用配置好的通知类bean的id。 |
aop:advisor | 作用:用于配置切面 | 区别一个是引用普通的bean一个是引用bean必须事先advice接口 |
aop:pointcut | 用于配置切入点表达式 | expression:用于定义切入点表达式。 id:用于给切入点表达式提供一个唯一标识。 |
aop:before | 用于配置前置通知 | method:指定通知中方法的名称 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 |
aop:after-returning | 用于配置后置通知,如果出了异常就一定不会调用切面的方法 | method:指定通知中方法的名称。 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 |
aop:after-throwing | 用于配置异常通知,只有出了异常才会调用切面对应的方法 | method:指定通知中方法的名称 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 |
aop:after | 用于配置最终通知,不管出不出异常,调用的切面的方法 | method:指定通知中方法的名称。 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 |
aop:around | 用于配置环绕通知 | method:指定通知中方法的名称。 pointct:定义切入点表达式 pointcut-ref:指定切入点表达式的引用 |
注解方式
首先bean.xml文件添加相应配置
<context:component-scan base-package="xxx" />//IOC自动扫包 <aop:aspectj-autoproxy /> //开启Spring AOP注解方式首先要配置<aop:aspectj-autoproxy/>标签,Spring提供了JDK动态代理和CGLIB代理两种方式为目标类创建代理,默认情况下,如果目标类实现了一个以上的用户自定义的接口或者目标类本身就是接口,就会使用JDK动态代理,如果目标类本身不是接口并且没有实现任何接口,就会使用CGLIB代理,如果想强制使用CGLIB代理,则可以将属性proxy-target-class设置true,这两种代理方式在使用的时候有一些需要注意的事项,JDK动态代理是基于实现目标类的接口来创建代理类的,所以只有接口方法会被代理,其他方法不会被代理,而CGLIB代理是基于继承目标类实现的,所以不能被继承的方法(例如final修饰的方法、private修饰的方法等)是不能被代理的,建议尽量使用JDK动态代理的方式创建代理类 expose-proxy属性用来解决对象内部this调用无法被切面增强的问题,例如我们在A类的对象内部x方法中调用另外一个内部方法y时,y方法不会被切面增强,这时可以配置expose-proxy为true并将this.y()改为((A)AopContext.currentProxy()).y(),即可让y方法被切面增强 JDK动态代理与cglib动态代理区别 jdk创建对象的速度远大于cglib,这是由于cglib创建对象时需要操作字节码。cglib执行速度略大于jdk,所以比较适合单例模式。另外由于CGLIB的大部分类是直接对Java字节码进行操作,这样生成的类会在Java的永久堆中。如果动态代理操作过多,容易造成永久堆满,触发OutOfMemory异常。
(1)Before:在目标方法被调用之前做增强处理,@Before只需要指定切入点表达式即可
(2)AfterReturning:在目标方法正常完成后做增强,@AfterReturning除了指定切入点表达式后,还可以指定一个返回值形参名returning,代表目标方法的返回值
(3)AfterThrowing:主要用来处理程序中未处理的异常,@AfterThrowing除了指定切入点表达式后,还可以指定一个throwing的返回值形参名,可以通过该形参名
来访问目标方法中所抛出的异常对象
(4)After:在目标方法完成之后做增强,无论目标方法时候成功完成。@After可以指定一个切入点表达式
(5)Around:环绕通知,在目标方法完成前后做增强处理,环绕通知是最重要的通知类型,像事务,日志等都是环绕通知,注意编程中核心是一个ProceedingJoinPoint
<?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" xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd "> <bean name="student1" class="dasd.pojo.Student" > <property name="id" value="1"> </property> <property name="name" value="afeng"> </property> </bean> <bean id="teacher1" class="dasd.pojo.Teacher" > <property name="id" value="1"> </property> <property name="name" value="afeng"> </property> </bean> <bean id="StudentService" class="dasd.service.impl.StudentService"></bean> <!--<aop:config> <aop:pointcut id="pointcut" expression="execution(public void dasd.service.impl.StudentService.doSome(..)) "></aop:pointcut> <aop:aspect id="stuAsp" ref="stuAsp"> <aop:before method="before" pointcut-ref="pointcut"/> <aop:after-returning method="after" pointcut-ref="pointcut"/> <aop:after-throwing method="throwAfter" pointcut-ref="pointcut"/> <aop:after method="AfterFinally" pointcut-ref="pointcut"/> <aop:around method="around" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>--> <context:component-scan base-package="dasd" /> <aop:aspectj-autoproxy /> </beans>
package dasd.asp; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class StudentAsp { @Pointcut("execution(public void dasd.service.impl.StudentService.doSome(..))") public void aspect(){ } @Before("aspect()") public void before(){ System.out.println("我在方法前做事情"); } @AfterReturning("aspect()") public void after(){ System.out.println("我在正常方法后做事情"); } @AfterThrowing("aspect()") public void throwAfter(){ System.out.println("我在方法抛异常后做事情"); } @After("aspect()") public void AfterFinally(){ System.out.println("我始终在方法后做事情"); } @Around("aspect()") public void around(){ System.out.println("我环绕方法做事情"); } }
小区别:两只方式运行的结果是不一样的,但是一般不会用多种方式。无伤大雅
什么时候用aop
-
当你不想改变原有实现类的时候
-
当你想批量对某些类做特定的一件事情的时候你就要用到
福利:利用aop进行日志输出
前置后置
package aop; import java.util.Arrays; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Pointcut; /** * 使用注解定义切面 */ @Aspect public class UserServiceLogger { private static final Logger log = Logger.getLogger(UserServiceLogger.class); @Pointcut("execution(* service.UserService.*(..))") public void pointcut() {} @Before("pointcut()") public void before(JoinPoint jp) { log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs())); } @AfterReturning(pointcut = "pointcut()", returning = "returnValue") public void afterReturning(JoinPoint jp, Object returnValue) { log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法返回值:" + returnValue); } }
异常抛出
package aop; import org.apache.log4j.Logger; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; /** * 通过注解实现异常抛出增强 */ @Aspect public class ErrorLogger { private static final Logger log = Logger.getLogger(ErrorLogger.class); @AfterThrowing(pointcut = "execution(* service.UserService.*(..))", throwing = "e") public void afterThrowing(JoinPoint jp, RuntimeException e) { log.error(jp.getSignature().getName() + " 方法发生异常:" + e); } }
最终
package aop; import org.apache.log4j.Logger; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.After; /** * 通过注解实现最终增强 */ @Aspect public class AfterLogger { private static final Logger log = Logger.getLogger(AfterLogger.class); @After("execution(* service.UserService.*(..))") public void afterLogger(JoinPoint jp) { log.info(jp.getSignature().getName() + " 方法结束执行。"); } }
环绕(最棒的)
package aop; import java.util.Arrays; import org.apache.log4j.Logger; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; /** * 通过注解实现环绕增强 */ @Aspect public class AroundLogger { private static final Logger log = Logger.getLogger(AroundLogger.class); @Around("execution(* service.UserService.*(..))") public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.info(simpleDateFormat.format(new Date())+"调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs())); try { Object result = jp.proceed(); log.info("调用 " + jp.getTarget() + " 的 " + jp.getSignature().getName() + " 方法。方法返回值:" + result); return result; } catch (Throwable e) { log.error(jp.getSignature().getName() + " 方法发生异常:" + e); throw e; } finally { log.info(simpleDateFormat.format(new Date()).toString()+jp.getSignature().getName() + " 方法结束执行。"); } } }
JoinPoint jp与 ProceedingJoinPoint解释
import org.aspectj.lang.reflect.SourceLocation; public interface JoinPoint { String toString(); //连接点所在位置的相关信息 String toShortString(); //连接点所在位置的简短相关信息 String toLongString(); //连接点所在位置的全部相关信息 Object getThis(); //返回AOP代理对象 Object getTarget(); //返回目标对象 Object[] getArgs(); //返回被通知方法参数列表 Signature getSignature(); //返回当前连接点签名 SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置 String getKind(); //连接点类型 StaticPart getStaticPart(); //返回连接点静态部分 } public interface ProceedingJoinPoint extends JoinPoint { public Object proceed() throws Throwable; //让目标方法执行 public Object proceed(Object[] args) throws Throwable; }
引入其他配置文件
<!-- Spring中引入其他配置文件 --> <import resource="classpath*:xxx.xml" />