目录
Spring 两大核心技术
- 控制反转(IoC:Inversion of Control ) /依赖注入(DI:Dependency Injection )
- 面向切面编程(AOP:Aspect Oriented Programming)
Spring的优点
- 低侵入式设计
- 独立于各种应用服务器
- 依赖注入特性将组件关系透明化,降低了耦合度
- 面向切面编程特性允许将通用任务进行集中式处理
- 与第三方框架的良好整合
控制反转
控制反转: 将组件对象的控制权从代码本身转移到外部容器(其实就是把new对象放到了配置文件里)。
组件化的思想:分离关注点,使用接口,不再关注实现。
依赖的注入:将组件的构建和使用分开。
依赖注入:指spring创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象。
- 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
- 反转 : 程序本身不创建对象 , 而变成被动的接收对象
---------------------------------------------------------------------------------------------
步骤
1、引入jar包
<spring.version>4.0.2.RELEASE</spring.version>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
2、创建HelloWorld类
public class HelloWorld {
private String message;
public void show(){
System.out.println(message);
}
public void setMessage(String message) {
this.message = message;
}
}
3、创建spring配置文件spring.xml
4、引入头部信息
5、编写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"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- HelloWorld测试 -->
<bean id="helloWorld" class="com.hz.pojo.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
6、编写测试类
public class TestHelloWorld {
@Test
public void TestHelloWorld(){
//使用ClassPathXmlApplicationContext读取配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
//使用getBean("bean中ID属性值")获取对象
HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
helloWorld.show();
}
}
Spring IOC常用注解:
@Component:实现Bean组件的定义
@Repository([实例化名称]) :用于标注DAO类
@Service([实例化名称]) :用于标注业务类
@Controller :用于标注控制器类 @Autowired+@Qualifier("userDao")等价于@Resource(name = "userDao")
使用注解前需先开启注解:
<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/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
详细学习参考文章:Spring全面详解
纯注解开发:
使用
@Configuration注解用于设定当前类为配置类
@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式
----------------------------------------------------------------------
bean标签解释:
依赖注入的方式:
1、set注入
<bean id="helloWorld" class="com.hz.pojo.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
2、构造函数注入
<bean>实例化对象默认调用无参构造函数
eg:
<bean id="userDao" class="com.hz.dao.impl.UserDaoImpl"></bean>
<bean id="userService" class="UserServiceImpl">
<constructor-arg >
<ref bean="userDao"></ref>
</constructor-arg>
</bean>
3、p命名空间注入
<bean id="userDao" class="com.hz.dao.impl.UserDaoImpl"/> <bean id="userService" p:userDao-ref="userDao" class="com.hz.service.UserServiceImpl"/>
4..注入数组,字符串,集合.....各种类型
private String specialCharacter1; // 特殊字符值1
private String specialCharacter2; // 特殊字符值2
private User 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值
<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>
----------------------------------------------------------------------
自动装配:autowrite,用于引用类型依赖注入,不能对简单类型进行操作,优先级低于setter注入与构造器注入。
byType:按类型装配,必须保障容器中相同类型的bean唯一
byName:按名称装配,必须保障容器中具有指定名称的bean
加载properties文件
面向切面编程(AOP)
所谓面向切面编程,是一种通过预编译和运行期动态代理的方式实现在不修改源代码的情况下给程序动态添加功能的技术(即公共功能集中解决)。
原理:
- 将复杂的需求分解出不同方面,将散布在系统中的公共功能(eg:异常处理、日志、事务等)集中解决
- 采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能
AOP中的概念:
- 切入点(Pointcut): 在哪些类,哪些方法上切入(where)
- 通知(Advice): 在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强 的功能)
- 切面(Aspect): 切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!
- 织入(Weaving): 把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
五种增强方式:
目录 | 说明 | 使用 |
前置增强 | 在一个方法执行之前 | before |
后置增强 | 在一个方法执行之后,不考虑其结果,执行通知。 | after- returning |
最终增强 | 在一个方法执行之后,只有在方法成功完成时,才能执行通知。 | after |
异常增强 | 在一个方法执行之后,只有在方法退出抛出异常时,才能执行通 知 | after-throwing |
环绕增强 | 在一个方法执行之前,执行通知。 | around |
使用:
创建增强处理类 LoggerAop
(这里使用的是注解开发,不使用注解开发的话)
package com.hz.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 注解定义切面
*
*/
@Aspect
@Component
public class LoggerAop {
//用于打印日志信息
private static Logger log=Logger.getLogger(LoggerAop.class);
@Pointcut("execution(* com.hz.service..*.*(..))")
public void pointcut(){}
@Before("pointcut()")
public void before(JoinPoint jp) {
System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().
getName() + " 方法。方法入参:" + Arrays.toString(jp.getArgs()));
}
@AfterReturning(pointcut = "pointcut()",returning ="result")
public void afterReturning(JoinPoint jp, Object result) {
System.out.println("调用 " + jp.getTarget() + " 的 " + jp.getSignature().
getName() + " 方法。方法返回值:" + result);
}
@AfterThrowing(pointcut = "pointcut()",throwing ="re")
public void afterThrowing(RuntimeException re){
System.out.println("这是一场增强..."+re);
}
@After("pointcut()")
public void after(){
System.out.println("这是最终增强。。。");
}
}
引入xml头部
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<aop:config>
<!--定义切入点-->
<aop:pointcut id="pointcut" expression="execution(public void show())"/>
<!--织入增强处理-->
<aop:aspect ref="serviceLogger">
<!--使用前置增强,将切入点与before方法绑定-->
<aop:before method="before" pointcut-ref="pointcut"></aop:before>
<!--使用后置增强,将切入点与before方法绑定 returning 返回参数接收-->
<aop:after-returning method="afterReturning" pointcut-ref="pointcut"
returning="result"/>
</aop:aspect>
</aop:config>
AOP注解
开启注解:
<!--扫包 使用注解开发--> <context:component-scan base-package="com.hz.dao,com.hz.service,com.hz.aop"/> <!--开启注解--> <aop:aspectj-autoproxy />
**/**
* 使用注解定义切面
*/
@Aspect
@Component
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);
}
}