spring
spring
文章目录
- spring
- 1.spring是什么?
- 2.为什么要使用spring
- 3.搭建spring-maven环境
- 3.4 创建一个spring.xml配置文件,配置bean
- 3.5 单元测试 junit
- 4.spring容器的简单实现
- 应用技术:
- 具体步骤
- 代码体现:
- 4.1 引入相关依赖
- 4.2 配置spring全局配置文件
- 4.3 创建java类
- 4.4 创建接口,获取bean实例的接口
- 4.5 创建实现类
- 4.6 用到的vo 类
- 4.7 测试
- 5.Spring 多文件加载情况
- 6.Spring Loc 实例化 bean对象的三种方式
- 6.1 构造器的方式实例化bean对象
- 6.2 静态工厂方法方式实例化 bean
- 6.3 实例化工厂方式创建Bean
- 实例化工厂定义
- Bean配置
- 6.4 spring 三种实例化 bean 的方式比较
- 7.Spring 依赖注入(Dependency Injection 即 DI)
- 8.注解方式注入bean
- 8.1 加入 spring-aop jar 包 spring-aop-4.3.2.RELEASE.jar
- 8.2 Xml 配置: 加入 context 命名空间 和 xsd 地址
- 8.3 添加< >配置
- 8.4 注解区别
- 9.Spring Ioc 容器自动扫描管理 bean
- 10.Bean 的作用域
- 11.Bean的生命周期
- 12.代理模式
- 13. 理解 Aop(jdk+cglib )
- 14. Aop 基本概念
- 14.1 Joinpoint(连接点)
- 14.2 Pointcut(切入点)
- 14.3 Advice(通知)
- 14.4 Aspect(切面)
- 14.5 Target(目标对象)
- 14.6 Weave(织入)
- 14.7 Introduction(引入)
- 15 使用 Aop 解决日志处理问题
- 16. Spring 定时任务
- 17 Java-邮件发送
- 18 spring 整合 jdbc
- 19. Spring Jdbc 事务管理配置
- 20.远程方法调用RMI
1.spring是什么?
众多开源 java 项目中的一员,基于分层的 javaEE 应用一站式轻量级开源框架,主要核心是 Ioc(控制反转/依赖注入) 与 Aop(面向切面)两大技术,实现项目在开发过程中的轻松解耦,提高项目的开发效率。
2.为什么要使用spring
-
轻量:Spring 是轻量的,基本的版本大约2MB。
-
控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
-
面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
-
**容器:**Spring 包含并管理应用中对象的生命周期和配置。
-
**事务管理:**Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)
-
**异常处理:**Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。
3.搭建spring-maven环境
3.1 创建一个maven的普通工程 quickstart
3.2 引用pom.xml依赖
<?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>com.shsxt</groupId>
<artifactId>spring02</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring02</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
</dependencies>
<build>
</build>
</project>
3.3 创建一个bean
UserDao.java
package com.shsxt.dao;
public class UserDao {
public void add(String name, Integer passpwd){
System.out.println("add:"+name+" "+passpwd);
}
}
HelloService.java
package com.shsxt.service;
public class HelloService {
public void hello(){
System.out.println("hello spring");
}
}
3.4 创建一个spring.xml配置文件,配置bean
spring02.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">
<!--
xmlns 即 xml namespace xml 使用的命名空间
xmlns:xsi 即 xml schema instance xml 遵守的具体规范
xsi:schemaLocation 本文档 xml 遵守的规范 官方指定
-->
<bean id="helloService" class="com.shsxt.service.HelloService"></bean>
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
</beans>
3.5 单元测试 junit
package com.shsxt;
import com.shsxt.service.HelloService;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestSpring {
@Test
public void test01(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring02.xml");
HelloService helloService = (HelloService) context.getBean("helloService");
helloService.hello();
}
}
4.spring容器的简单实现
应用技术:
具体步骤
1.读取xml配置文件
2.通过配置信息创建类的实例
3.存储实例以及取出实例
注意: 配置文件中 不能引用外部网站
代码体现:
4.1 引入相关依赖
<?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>com.shsxt</groupId>
<artifactId>spring03</artifactId>
<version>1.0-SNAPSHOT</version>
<name>spring03</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
</dependencies>
<build>
</build>
</project>
4.2 配置spring全局配置文件
spring03.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="userDao" class="dao.UserDao"></bean>
</beans>
4.3 创建java类
package dao;
public class UserDao {
public void userDao(){
System.out.println("helle");
}
}
4.4 创建接口,获取bean实例的接口
public interface ApplicationContext {
public Object getBean(String id);
}
4.5 创建实现类
package com.shsxt;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SxtApplicationContext implements ApplicationContext {
/**
* 1.读取xml配置文件
* 2.生成Bean实例
* 3.取出bean
* @param id
* @return
*/
private String path;
private List<SxtBean> beanList = new ArrayList<>();
private Map<String,Object> map = new HashMap<>();
public SxtApplicationContext(String path) {
this.path = path;
parseXml(path);
createBean();
}
/**
* 取出bean
* @param id
* @return
*/
public Object getBean(String id){
return map.get(id);
}
/**
* 生成相应的Bean
*/
private void createBean() {
if (beanList!=null && beanList.size()>0){
for (SxtBean sxtBean: beanList){
try {
map.put(sxtBean.getId(),Class.forName(sxtBean.getClazz()).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
/**
* 解析配置文件xml
* @param path
*/
private void parseXml(String path) {
SAXReader reader = new SAXReader();
if (null!=path && !"".equals(path)){
URL url = this.getClass().getClassLoader().getResource(path);
try {
Document document = reader.read(url);
List<Element> list = document.selectNodes("//beans/bean");
for (Element element:list){
SxtBean sxtBean = new SxtBean();
sxtBean.setId(element.attributeValue("id"));
sxtBean.setClazz(element.attributeValue("class"));
beanList.add(sxtBean);
}
} catch (DocumentException e) {
e.printStackTrace();
}
}else {
System.out.println("文件不存在");
}
}
}
4.6 用到的vo 类
SxtBean.java
package com.shsxt;
public class SxtBean {
private String id; //xml中对应的 id属性
private String clazz; //xml中对应的 class属性
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
4.7 测试
package com.shsxt;
import dao.UserDao;
import org.junit.Test;
import static org.junit.Assert.*;
public class ContextTest {
@Test
public void test(){
ApplicationContext context = new SxtApplicationContext("spring03.xml");
UserDao userDao = (UserDao) context.getBean("userDao");
userDao.userDao();
}
}
5.Spring 多文件加载情况
Spring 框架启动时可以加载多个配置文件到环境中。对于比较复杂的项目,可能对应
的配置文件有多个,项目在启动部署时会将多个配置文件同时加载进来
Dao.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="userDao" class="com.shsxt.dao.UserDao"></bean>
</beans>
Service.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="userService" class="com.shsxt.service.UserService"></bean>
</beans>
Controller.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="userController"
class="com.shsxt.comtroller.UserController"></bean>
</beans>
测试
@Test
public void test01() throws Exception{
ApplicationContext ac=new
ClassPathXmlApplicationContext("dao.xml","service.xml","controller.xml");
// 获取 dao 层 bean
UserDao userDao=(UserDao) ac.getBean("userDao");
userDao.save();
//获取 service 层 bean
UserService userService= (UserService) ac.getBean("userService");
userService.hello();
// 获取 controller bean
UserController userController=(UserController)
ac.getBean("userController");
userController.show();
}
6.Spring Loc 实例化 bean对象的三种方式
6.1 构造器的方式实例化bean对象
<bean id="userServiceImpl"
class="com.shsxt.service.impl.UserServiceImpl"></bean>
通过默认构造器创建 空构造方法必须存在 否则创建失败
6.2 静态工厂方法方式实例化 bean
1.要有该工厂类及工厂方法
2.工厂方法为静态的
静态工厂定义
package com.shsxt.factory;
import com.shsxt.service.UserService;
public class StaticFactory {
public static UserService createUserService(){
return new UserService();
}
}
Bean配置
<bean id="userService" class="com.shsxt.factory.StaticFactory"
factory-method="createUserService"/>
当我们指定 Spring 使用静态工厂方法来创建 Bean 实例时,Spring 将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,并将该静态工厂方法的返回值作为 Bean 实例,在这个过程中,Spring 不再负责创建 Bean 实例,Bean 实例是由用户提供的静态工厂方法提供的.
6.3 实例化工厂方式创建Bean
相比较静态工厂实现
I.工厂方法为非静态方法
II.需要配置工厂 bean,并在业务 bean 中配置 factory-bean,factory-method 属性
实例化工厂定义
package com.shsxt.factory;
import com.shsxt.service.UserService;
public class InstanceFactory {
public UserService createUserService(){
return new UserService();
}
}
Bean配置
<!--实例化工厂
1.定义实例化工厂 bean
2.引用工厂 bean 指定工厂创建方法(方法为非静态)
-->
<bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory"></bean>
<bean id="userService" factory-bean="instanceFactory"
factory-method="createUserService"></bean>
6.4 spring 三种实例化 bean 的方式比较
方式一:通过 bean 的缺省构造函数创建,当各个 bean 的业务逻辑相互比较独立的时
候或者和外界关联较少的时候可以使用
方式二:利用静态 factory 方法创建,可以统一管理各个 bean 的创建,如各个 bean 在
创建之前需要相同的初始化处理,则可用这个 factory 方法险进行统一的处理等等
方式三:利用实例化 factory 方法创建,即将 factory 方法也作为了业务 bean 来控制,
1 可用于集成其他框架的 bean 创建管理方法,2 能够使 bean 和 factory 的角色互换。
开发中项目一般使用一种方式实例化 bean,项目开发基本采用第一种方式,交
给 spring 托管,使用时直接拿来使用即可
7.Spring 依赖注入(Dependency Injection 即 DI)
Spring 支持的注入方式:set注入,构造器注入,静态工厂注入, 实例化工厂注入
7.1 Set注入
xml配置(支持基本数据类型set注入)
<?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="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
</beans>
Java类
package com.shsxt.service.impl;
import com.shsxt.dao.UserDao;
import com.shsxt.vo.User;
public class UserServiceImpl {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
public void saveUser(User user){
System.out.println("userName:"+userName+"price:"+price);
userDao.add(user);
}
}
基本数据类型set注入
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
<property name="userName" value="sxt"></property>
<property name="price" value="123"></property>
</bean>
同时对应 Service 提供对应属性字段 以及 get 、set 方法即可
7.2 构造器注入
xml配置(也提供对于基本数据类型,字符串等值的注入)
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
<bean id="userServiceImpl2" class="com.shsxt.service.impl.UserServiceImpl2">
<constructor-arg ref="userDao"></constructor-arg>
</bean>
Java类提供构造函数
package com.shsxt.service.impl;
import com.shsxt.dao.UserDao;
import com.shsxt.vo.User;
public class UserServiceImpl2 {
private UserDao userDao;
public UserServiceImpl2(UserDao userDao) {
this.userDao = userDao;
}
public void saveUser(User user){
userDao.add(user);
}
}
构造器注入字符串值
Index 属性为参数顺序 如果只有一个参数 index 可以不设置
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<constructor-arg name="userName" index="0" value="123"></constructor-arg>
<constructor-arg name="userPwd" index="1" value="321"></constructorarg>
</bean>
7.3 静态工厂注入
xml配置
<bean id="userDao" class="com.shsxt.factory.StaticFactory"
factory-method="createUserDao"></bean>
<bean id="userService" class="com.shsxt.service.UserService">
<property name="userDao" ref="userDao"></property>
</bean>
java类
package com.shsxt.factory;
import com.shsxt.dao.UserDao;
public class StaticFactory {
public static UserDao createUserDao(){
return new UserDao();
}
}
和set注入的区别只是获取bean的方式不同
7.4 实例化工厂
和set注入的区别只是获取bean的方式不同
7.5 p标签和 c标签
//简化set注入
xmlns:p="http://www.springframework.org/schema/p"
<bean id="userDao" class="com.shsxt.dao.UserDao"></bean>
<bean id="userService" class="com.shsxt.service.UserService"
p:userDao-ref="userDao"
p:age="20"
p:uname="sxt"
> </bean>
//简化构造器注入
xmlns:c="http://www.springframework.org/schema/c"
<bean id="userService" class="com.shsxt.service.UserService"
c:userDao-ref="userDao"
c:age="20"
c:uname="sxt"
/>
7.6 集合注入
–list集合注入
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<property name="list">
<list>
<value>河南烩面</value>
<value>南方臊子面</value>
<value>油泼面</value>
<value>方便面</value>
</list>
</property
</bean>
–set集合注入
<bean id="userServiceImpl"
class="com.shsxt.service.impl.UserServiceImpl">
<property name="set">
<set>
<value>快乐小馒头</value>
<value>北方馒头</value>
<value>天津麻花</value>
<value>*大饼</value>
</set>
</property>
</bean>
–map类型属性注入
<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl">
<property name="map">
<map>
<entry>
<key><value>河南</value></key>
<value>云台山风景</value>
</entry>
<entry>
<key><value>上海</value></key>
<value>宝塔</value>
</entry>
<entry>
<key><value>北京</value></key>
<value>紫禁城</value>
</entry>
</map>
</property>
</bean>
–properties属性注入
<bean id="userServiceImpl"
class="com.shsxt.service.impl.UserServiceImpl">
<property name="prop">
<props>
<prop key="北京">北京尚学堂</prop>
<prop key="上海">上海尚学堂</prop>
<prop key="西安">西安尚学堂</prop>
</props>
</property>
</bean>
8.注解方式注入bean
注解的配置简化开发的速度,使程序看上去更简洁。
8.1 加入 spring-aop jar 包 spring-aop-4.3.2.RELEASE.jar
8.2 Xml 配置: 加入 context 命名空间 和 xsd 地址
8.3 添加<context:annotation-config/ >配置
<?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:annotation-config/>
</beans>
对于 bean 的注入常用注解类型
@Autowired 属性字段或 set 方法上
@Resource 属性字段上或 set 方法上
8.4 注解区别
@Autowired 默认按 bean 的类型匹配 可以修改 按名称匹配 和@Qualifier 配合使用
@Resource 默认按名称进行装配,名称可以通过 name 属性进行指定,如果没有指定 name 属性,当注解写在字段上时,默认取字段名进行匹配注入,如果注解写在 setter 方法上默认取属性名进行装配。当找不到与名称匹配的 bean时才按照类型进行装配。但是需要注意的是,如果 name 属性一旦指定,就只会按照名称进行装配。
推荐使用@Resource 注解是属于 J2EE 的,减少了与 spring 的耦合
9.Spring Ioc 容器自动扫描管理 bean
//自动扫描 com.shsxt下的所有类
<context:component-scan base-package="com.shsxt"/>
同时对于被 spring 管理的 bean 类的定义上需要加入对应的注解定义
Dao层:@Repository
Service层:@Service
视图控制层: @Controller
如果对于开发的类实在不明确到底属于哪个层,可以使用@Component 注解定义
10.Bean 的作用域
10.1 singleton 作用域 (默认设置是单例)
<bean id="bean" class="...." lazy-init="true"></bean>
注意: lazy-init 是懒加载, 如果等于 true 时作用是指 spring 容器启动的时候不会去实例化这个 bean, 而是在程序调用时才去实例化. 默认是 false 即 spring 容器启动时实例化
容器在启动的情况下就实例化所有 singleton 的 bean 对象,并缓存与容器中
单例的好处:
1)提前发现潜在的配置问题
2)Bean 对象存在于缓存中,使用时不用再去实例化 bean,加快程序运行效率
一般来说对于无状态或状态不可改变的 对象适合使用单例模式(什么是无状态或状态
不可改变)
10.2 prototype 作用域
<bean id="bean" class="..." scope="prototype"></bean>
通过 scope=” prototype” 设置 bean 的类型 ,每次向 Spring 容器请求获取Bean 都返回一个全新的 Bean,相对于“singleton”来说就是不缓存 Bean,每次都是一个根据 Bean 定义创建的全新 Bean。
10.3 Web 应用中的作用域(request、session、globalsession)
request 作用域:表示每个请求需要容器创建一个全新 Bean。比如提交表单的数据必须是对每次请求新建一个 Bean 来保持这些表单数据,请求结束释放这些数据。
session 作用域:表示每个会话需要容器创建一个全新 Bean。比如对于每个用户一般会有一个会话,该用户的用户信息需要存储到会话中,此时可以将该 Bean 作用域配置为 session 级别。
globalSession:类似于 session 作用域,其用于 portlet(Portlet 是基于 Java的 Web 组件,由 Portlet 容器管理,并由容器处理请求,生产动态内容)环境的 web 应用。如果在非 portlet 环境将视为 session 作用域。
11.Bean的生命周期
11.1 Bean 的定义
对比 servlet 生命周期(容器启动装载并实例化 servlet 类,初始化servlet,调用 service 方法,销毁 servlet)。同样对于 spring 容器管理的 bean 也存在生命周期的概念。
Bean的Java类的创建就是Bean的定义
11.2 Bean的初始化
Spring bean 初始化有两种方式:
I.在配置文档中通过指定 init-method 属性来完成
II.实现 org.springframework.beans.factory.InitializingBean 接口。
<bean id="userServiceImpl"class="com.shsxt.service.impl.UserServiceImpl"
init-method="init" >
11.3 Bean 的使用
I.使用 BeanFactory
II.使用 ApplicationContext
11.4 Bean 的销毁
实现销毁方式(spring 容器会维护 bean 对象的管理,可以指定 bean 对象的销毁所要执行的方法)
<bean id="userServiceImpl"class="com.shsxt.service.impl.UserServiceImpl" init- method="init" destroy-method="destroy">
</bean>
通过 AbstractApplicationContext 对象,调用其 close 方法实现 bean 的销毁过程。
AbstractApplicationContext ctx=new ClassPathXmlApplicationContext("springapplication.xml");
ctx.close();
12.代理模式
代理模式在 java 开发中是一种比较常见的设计模式。设计目的旨在为服务类与客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。如租房的例子 房客、中介、房东。对应于代理模式中即:客户类 代理类 委托类(被代理类)
代理模式的两个设计原则:
- 代理类 与委托类具有相似的行为(共同)
- 代理类增强委托类的行为
代理模式分为两类:静态代理和动态代理及批量化代理(aop)
12.1 静态代理
为某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理.
定义接口:
package com.shsxt.test;
/**
*
* 接口 抽象角色
* 定义行为
*/
public interface Marry {
public void toMarry();
}
委托类:
package com.shsxt.test;
/**
* 目标类 真实角色
*/
public class You implements Marry{
@Override
public void toMarry() {
System.out.println("等了这么久,终于等到你。。。");
}
}
代理类:
package com.shsxt.test;
/**
*
* 代理类 代理角色
* 1.与目标角色实现共同接口
* 2.持有目标类的引用
* 3.增强目标角色行为
*/
public class MarryCompany implements Marry{
// 目标角色引用
private Marry target;
public MarryCompany(Marry target) {
this.target = target;
}
public void before(){
System.out.println("婚礼现场紧张布置中......");
}
@Override
public void toMarry() {
before();
target.toMarry();
after();
}
public void after(){
System.out.println("恭喜您成功进入人生第二阶段.....");
}
}
测试:
package com.shsxt.test;
public class Test {
public static void main(String[] args) {
// 构造代理角色同时传入真实角色
MarryCompany marryCompany=new MarryCompany(new You());
marryCompany.toMarry();
}
}
静态代理对于代理的角色是固定的,如 dao 层 20 个 dao 类,如果要对方法的访问权限进行代理,此时需要创建 20 个静态代理角色,引起类爆炸,无法满足生产上的需要,于是就催生了动态代理的思想。
12.2 动态代理
相比于静态代理,动态代理在创建代理对象上更加的灵活,它会根据需要通过反射机制在程序运行期动态的为目标对象创建代理对象,代理的行为可以代理多个方法,即满足生产需要的同时又达到代码通用的目的。
动态代理的两种实现方式
I.jdk 实现动态代理。
package com.shsxt.test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* jdk 动态代理
*
*/
public class JdkHandler implements InvocationHandler{
// 目标类
private Object target;
public JdkHandler(Object target) {
this.target = target;
}
/**
* 程序运行期动态创建代理角色
* @return
*/
public Object getProxy(){
/**
* 获取代理对象
* 1.类加载器
* 2.目标类 实现的接口 class
* 3.当前类
* @return
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
public void before(){
System.out.println("婚礼现场紧张布置中......");
}
@Override
public Object invoke(Object proxy, Method method, Object[]
args) throws Throwable {
before();//增强真实角色行为
Object result= method.invoke(target, args);// 执行真实角色方
法
after();//增强真实角色行为
return result;
}
public void after(){
System.out.println("恭喜您成功进入人生第二阶段.....");
}
}
II.cglib 动态代理实现(了解)
code generator library ,操作字节码。 与 jdk 提供的代理区别,Proxy:委托类必须有接口,制作过程比较快,执行慢;cglib:委托类可以没有接口,继承的思维来实现相似性,制作代理过程比较慢,执行快。主要解决没有接口类的代理实现.
package com.shsxt.test;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibInterceptor implements MethodInterceptor {
private Object target;
public CglibInterceptor(Object target) {
this.target = target;
}
// 运行期动态创建代理类
public Object getProxy(){
Enhancer enhancer=new Enhancer();
//设置父类 class
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public void before(){
System.out.println("婚礼现场紧张布置中......");
}
@Override
public Object intercept(Object arg0, Method arg1, Object[]
arg2,MethodProxy arg3) throws Throwable {
before();//增强真实角色行为
Object result= arg3.invoke(target, arg2);
after();//增强真实角色行为
return result;
}
public void after(){
System.out.println("恭喜您成功进入人生第二阶段.....");
}
}
12.3 二者区别
Proxy委托类必须有接口 制作过程比较快 执行慢
Proxy委托类可以没有接口,继承的思想来实现相似性,制作过程比较慢,执行快,主要解决没有接口类的代理实现
13. 理解 Aop(jdk+cglib )
13.1 Aop 是什么?
Aspect Oriented Programing 面向切面编程
相比较 oop 面向对象编程来说,Aop 关注的不再是程序代码中某个类,某些方法,而 aop 考虑的更多的是一种面到面的切入 即层与层之间的一种切入,所以称之为切面。
13.2 Aop 能做什么?
AOP 主要应用于日志记录,性能统计,安全控制,事务处理等方面,实现公共功能性的重复使用.
13.3 Aop 带来的好处
- 降低模块与模块之间的耦合度,提高业务代码的聚合度。(高内聚低耦合)
- 提高了代码的复用性。
- 提高系统的扩展性。
14. Aop 基本概念
14.1 Joinpoint(连接点)
被拦截到的每个点,spring 中指被拦截到的每一个方法,springaop 一个连接点即代表一个方法的执行
14.2 Pointcut(切入点)
对连接点进行拦截的定义(匹配规则定义 规定拦截哪些方法,对哪些方法进行处理),spring 这块有专门的表达式语言定义。
14.3 Advice(通知)
拦截到每一个连接点即(每一个方法)后所要做的操作
i. 前置通知 (前置增强) --before() 执行方法前通知
ii.返回通知(返回增强)–afterReturn 方法正常结束返回后的通知
iii.异常抛出通知(异常抛出增强)–afetrThrow()
iv.最终通知—after 无论方法是否发生异常,均会执行该通知。
v.环绕通知—around 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行
14.4 Aspect(切面)
切入点与通知的结合,决定了切面的定义,切入点定义了要拦截哪些类的哪些方法,通知则定义了拦截过方法后要做什么,切面则是横切关注点的抽象,与类相似,类是对物体特征的抽象,切面则是横切关注点抽象。
14.5 Target(目标对象)
被代理的目标对象
14.6 Weave(织入)
将切面应用到目标对象并生成代理对象的这个过程即是织入。
14.7 Introduction(引入)
在不修改原有应用程序代码的情况下,在程序运行期为类动态添加方法或者字段的过程称为引入
15 使用 Aop 解决日志处理问题
Aop 配置有两种方式 注解方式 与 xml 方式
注解方式配置AOP
1.jar包坐标引入
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
2.beans.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代理
<aop:aspectj-autoproxy/>
3.编写aop类
package com.shsxt.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 声明切面组件
*/
@Component
@Aspect
public class LogCut {
/**
* 定义切入点 匹配方法规则定义
* 匹配规则表达式含义 拦截 com.shsxt.service 包下 以及子包下 所有类
的所有方法
*/
@Pointcut("execution (* com.shsxt.service..*.*(..))")
public void cut(){}
/**
* 声明前置通知 并将通知应用到定义的切入点上
* 目标泪方法执行前 执行该通知
*/
@Before(value="cut()")
public void before(){
System.out.println("前置通知.....");
}
/**
* 声明返回通知 并将通知应用到切入点上
* 目标类方法执行完毕执行该通知
*/
@AfterReturning(value="cut()")
public void afterReturning(){
System.out.println("返回通知....");
}
/**
* 声明最终通知 并将通知应用到切入点上
* 目标类方法执行过程中是否发生异常 均会执行该通知 相当于异常中的
finally
*/
@After(value="cut()")
public void after(){
System.out.println("最终通知....");
}
/**
* 声明异常通知 并将通知应用到切入点上
* 目标类方法执行时发生异常 执行该通知
*/
@AfterThrowing(value="cut()",throwing="e")
public void afterThrowing(Exception e){
System.out.println("异常通知....方法执行异常时执行:"+e);
}
/**
* 声明环绕通知 并将通知应用到切入点上
* 方法执行前后 通过环绕通知定义相应处理
*/
@Around(value="cut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕前置...");
System.out.println("环绕通知");
System.out.println(pjp.getTarget()+"--
"+pjp.getSignature());
Object result=pjp.proceed();
System.out.println("环绕后置...");
return result;
}
}
Aop 匹配方法规则表达式语言
执行任意公共方法:
execution(public *(..))
执行任意的 set 方法:
execution(* set*(..))
执行 com.xyz.service 包下任意类的任意方法
execution(* com.xyz.service.*.*(..))
执行 com.xyz.service 包 以及子包下任意类的任意方法
execution(* com.xyz.service..*.*(..))
XML配置实现aop
1.声明aop代理
2.配置切面,切入点,通知
xml
<!-- aop 相关配置 -->
<aop:config>
<!-- aop 切面配置 -->
<aop:aspect ref="logCut">
<!-- 定义 aop 切入点 -->
<aop:pointcut expression="execution (*
com.shsxt.service..*.*(..))" id="cut"/>
<!-- 配置前置通知 指定前置通知方法名 并引用切入点定义 -->
<aop:before method="before" pointcut-ref="cut"/>
<!-- 配置返回通知 指定返回通知方法名 并引用切入点定义 -->
<aop:after-returning method="afterReturning" pointcutref="cut"/>
<!-- 配置异常通知 指定异常通知方法名 并引用切入点定义 -->
<aop:after-throwing method="afterThrowing" throwing="e"
pointcut-ref="cut"/>
<!-- 配置最终通知 指定最终通知方法名 并引用切入点定义 -->
<aop:after method="after" pointcut-ref="cut"/>
<!-- 配置环绕通知 指定环绕通知方法名 并引用切入点定义 -->
<aop:around method="around" pointcut-ref="cut"/>
</aop:aspect>
</aop:config>
定义bean
package com.shsxt.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
/**
* 声明切面组件
*/
@Component
public class LogCut {
public void before(){
System.out.println("前置通知.....");
}
public void afterReturning(){
System.out.println("返回通知....");
}
public void after(){
System.out.println("最终通知....");
}
public void afterThrowing(Exception e){
System.out.println("异常通知....方法执行异常时执行:"+e);
}
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕前置...");
System.out.println("环绕通知");
System.out.println(pjp.getTarget()+"--"+pjp.getSignature());
Object result=pjp.proceed();
System.out.println("环绕后置...");
return result;
}
}
Spring Aop 面试中常见问题
1.代理模式实现三要素是什么?
i.接口定义
ii.目标对象 与代理对象必须实现统一接口
iii.代理对象持有目标对象的引用 增强目标对象行为
2.代理模式实现分类以及对应区别
静态代理:手动为目标对象制作代理对象,即在程序编译阶段完成代理对象的创建
动态代理:在程序运行期动态创建目标对象对应代理对象。
jdk 动态代理:被代理目标对象必须实现某一或某一组接口 实现方式 通过回调创建代理对象。
cglib 动态代理:被代理目标对象可以不必实现接口,继承的方式实现。动态代理相比较静态代理,提高开发效率,可以批量化创建代理,提高代码复用率。
3.Aop 理解
i. 面向切面,相比 oop 关注的是代码中的层 或面
ii. 解耦,提高系统扩展性
iii. 提高代码复用
4.Aop 关键词
- 连接点:每一个方法
- 切入点:匹配的方法集合
- 切面:连接点与切入点的集合决定了切面,横切关注点的抽象
- 通知:几种通知
- 目标对象:被代理对象
- 织入:程序运行期将切面应用到目标对象 并生成代理对象的过程
- 引入:在不修改原始代码情况下,在程序运行期为程序动态引入方法或字段的
过程
16. Spring 定时任务
一,基于xml方式定时任务的配置
1.定时任务命名空间的添加
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
2.定时任务方法代码
package com.shsxt.task;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.stereotype.Component;
@Component
public class TaskSchedule {
public void job1(){
System.out.println("任务 1:"+new SimpleDateFormat("yyyy-MM-dd
hh:mm:ss").format(new Date()));
}
public void job2(){
System.out.println("任务 2:"+new SimpleDateFormat("yyyy-MM-dd
hh:mm:ss").format(new Date()));
}
}
3.定时任务配置
<task:scheduled-tasks>
<!-- 每个两秒执行一次任务 -->
<task:scheduled ref="taskSchedule" method="job1" cron="0/2 * * * * ?"/>
<!-- 每隔五秒执行一次任务 -->
<task:scheduled ref="taskSchedule" method="job2" cron="0/5 * * * * ?"/>
<!-- 多个定时任务 在这里配置 -->
</task:scheduled-tasks>
二,基于注解的方式配置定时任务
1.在配置文件中添加命名空间
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
2.配置定时任务驱动
<task:annotation-driven />
3.定时任务代码
package com.shsxt.task;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class TaskSchedule {
@Scheduled(cron="0/2 * * * * ?")
public void job1(){
System.out.println("任务 1:"+new SimpleDateFormat("yyyy-MM-dd
hh:mm:ss").format(new Date()));
}
@Scheduled(cron="0/5 * * * * ?")
public void job2(){
System.out.println("任务 2:"+new SimpleDateFormat("yyyy-MM-dd
hh:mm:ss").format(new Date()));
}
}
Cron表达式:网上百度 在线Cron表达式
17 Java-邮件发送
17.1 JavaMail概述
JavaMail 是由 Sun 定义的一套收发电子邮件的 API,不同的厂商可以提供自己的实现类。但它并没有包含在 JDK 中,而是作为 JavaEE 的一部分。
常见的邮件协议包括:
SMTP:简单邮件传输协议,用于发送电子邮件的传输协议;
POP3:用于接收电子邮件的标准协议;
IMAP:互联网消息协议,是 POP3 的替代协议。
这三种协议都有对应 SSL 加密传输的协议,分别是 SMTPS,POP3S 和 IMAPS。
17.2 协议介绍
SMTP:
简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)由 RFC 821 定义。它定义了发送电子邮件的机制。在 JavaMail API 环境中,您基于 JavaMail 的程序将和您的公司或因特网服务供应商的(Internet Service Provider’s,ISP’s)SMTP 服务器通信。SMTP 服务器会中转消息给接收方 SMTP 服务器以便最终让用户经由 POP 或 IMAP 获得。
POP:
POP 代表邮局协议(Post Office Protocol)。目前用的是版本 3,也称 POP3,RFC 1939 定义了这个协议。POP 是一种机制,因特网上大多数人用它得到邮件。它规定每个用户一个邮箱的支持。这就是它所能做的,而这也造成了许多混淆。使用 POP3 时,用户熟悉的许多性能并不是由 POP 协议支持的,如查看有几封新邮件消息这一性能。这些性能内建于如 Eudora 或 Microsoft Outlook 之类的程序中,它们能记住一些事,诸如最近一次收到的邮件,还能计算出有多少是新的。所以当使用 JavaMail API 时,如果您想要这类信息,您就必须自己算。
IMAP:
IMAP 是更高级的用于接收消息的协议。在 RFC 2060 中被定义,IMAP 代表因特网消息访问协议(Internet Message Access Protocol),目前用的是版本 4,也称 IMAP4。在用到 IMAP 时,邮件服务器必需支持这个协议。不能仅仅把使用 POP 的程序用于 IMAP,并指望它支持 IMAP 所有性能。假设邮件服务器支持 IMAP,基于 JavaMail 的程序可以利用这种情况 — 用户在服务器上有多个文件夹(folder),并且这些文件夹可以被多个用户共享。因为有这一更高级的性能,您也许会认为所有用户都会使用 IMAP。事实并不是这样。要求服务器接收新消息,在用户请求时发送到用户手中,还要在每个用户的多个文件夹中维护消息。这样虽然能将消息集中备份,但随着用户长期的邮件夹越来越大,到磁盘空间耗尽时,每个用户都会受到损失。使用 POP,就能卸载邮件服务器上保存的消息了.
MIME:
MIME 代表多用途因特网邮件扩展标准(Multipurpose Internet MailExtensions)。它不是邮件传输协议。但对传输内容的消息、附件及其它的内容定义了格式。这里有很多不同的有效文档:RFC 822、RFC 2045、RFC 2046 和 RFC2047。作为一个 JavaMail API 的用户,您通常不必对这些格式操心。无论如何,一定存在这些格式而且程序会用到它。
17.3 JavaMail 的关键对象
Properties:属性对象
Session:会话对象
Transport 和 Store:传输和存储
Message:消息对象
Address:地址
Authenticator:认证者
17.4 Java mail 邮件发送实现
个人邮箱准备这里以(163 邮箱为例)
注册 163 邮箱,登录 163 邮箱后 设置邮箱账户开通 smtp 协议
登录到邮箱后 获取邮箱客户端授权码这里需要根据注册时输入的手机后输入 163 服务器发送的验证码来开通,开通成功 记住个人授权访问码会以短信通知到对应手机,该授权码是后面通过 Java mail 发送邮件的认证密码 非常重要 不要记错
jar下载
1.普通文本邮件发送
/**
* 发送普通文本
* @throws MessagingException
*/
public static void sendMail01() throws MessagingException {
/**
* 定义卫星
* 送卫星上天
* Message message=null;
* 火箭 送卫星上天
* Transport.send(message);
*
*/
Message message=null;// 卫星
// 定义邮箱服务器配置
Properties props=new Properties();
// 163 邮件服务器地址
props.put("mail.smtp.host", "smtp.163.com");
// 163 邮件服务器端口
props.put("mail.smtp.port", "25");
// 163 邮件服务器认证属性
props.put("mail.smtp.auth", "true");
Session session=Session.getInstance(props,new
MyAuthenticator03("163账号","授权密码"));
message=new MimeMessage(session);
// 设置发送人地址
Address from=new InternetAddress("发送人邮箱");
message.setFrom(from);
//目标用户邮箱地址
message.setRecipient(RecipientType.TO, new
InternetAddress("目的地邮箱));
message.setSentDate(new Date());// 设置发送日期
message.setSubject("java_mail 邮件发送测试");//设置主题
message.setText("hello Java mail");// 设置文本内容
Transport.send(message);// 火箭送卫星上天
2.发送html邮件
/**
* 发送 html 信息
* @throws MessagingException
*/
public static void sendMail02() throws MessagingException {
/**
* 定义卫星
* 火箭
* 送卫星上天
*/
Message message=null;// 卫星
// 定义邮箱服务器配置
Properties props=new Properties();
// 163 邮件服务器地址
props.put("mail.smtp.host", "smtp.163.com");
// 163 邮件服务器端口
props.put("mail.smtp.port", "25");
// 163 邮件服务器认证属性
props.put("mail.smtp.auth", true);
Session session=Session.getInstance(props,new
MyAuthenticator03("[email protected]","1qaz2wsx"));
message=new MimeMessage(session);
// 设置发送人地址
Address from=new InternetAddress("[email protected]");
message.setFrom(from);
//目标用户邮箱地址
message.setRecipient(RecipientType.TO, new
InternetAddress("[email protected]"));
message.setSentDate(new Date());// 设置发送日期
message.setSubject("html 邮件");//设置主题
Multipart multipart=new MimeMultipart();
BodyPart bodyPart=new MimeBodyPart();
StringBuffer sb=new StringBuffer();
sb.append("<html><body><a href='http://www.baidu.com'>百度一下
</a></body></html>");
bodyPart.setContent(sb.toString(), "text/html;charset=utf-8");
multipart.addBodyPart(bodyPart);
message.setContent(multipart);
Transport.send(message);// 火箭送卫星上天
}
3.发送邮件同时添加附件
/**
* 发送邮件同时添加附件
* @throws MessagingException
*/
public static void sendMail03() throws MessagingException{
/**
* 定义卫星
* 火箭
* 送卫星上天
*/
Message message=null;// 卫星
// 定义邮箱服务器配置
Properties props=new Properties();
// 163 邮件服务器地址
props.put("mail.smtp.host", "smtp.163.com");
// 163 邮件服务器端口
props.put("mail.smtp.port", "25");
// 163 邮件服务器认证属性
props.put("mail.smtp.auth", true);
Session session=Session.getInstance(props,new
MyAuthenticator03("[email protected]","1qaz2wsx"));
message=new MimeMessage(session);
// 设置发送人地址
Address from=new InternetAddress("[email protected]");
message.setFrom(from);
//目标用户邮箱地址
message.setRecipient(RecipientType.TO, new
InternetAddress("[email protected]"));
//message.setRecipient(RecipientType.CC, new
InternetAddress("[email protected]"));//设置抄送人
//message.setRecipient(RecipientType.BCC, new
InternetAddress("[email protected]"));// 设置密送人
message.setSentDate(new Date());// 设置发送日期
message.setSubject("附带附件邮件");//设置主题
Multipart multipart=new MimeMultipart();
BodyPart bodyPart=new MimeBodyPart();
StringBuffer sb=new StringBuffer();
sb.append("<html><body><a href='http://www.baidu.com'>百度一下
</a></body></html>");
bodyPart.setContent(sb.toString(), "text/html;charset=utf-8");
multipart.addBodyPart(bodyPart);
//添加附件内容
BodyPart bodyPart02=new MimeBodyPart();// 内容体 附件
FileDataSource fds=new FileDataSource(new File("C:\\java\\redis.txt"));
// 设置附件
bodyPart02.setDataHandler(new DataHandler(fds));
// 设置文件名
bodyPart02.setFileName(MimeUtility.encodeText("redis.txt"));
multipart.addBodyPart(bodyPart02);
message.setContent(multipart);
Transport.send(message);// 火箭送卫星上天
}
17.5 使用 Spring api 实现邮件发送
1.环境准备 这里建立maven普通工程
添加坐标依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring 核心 jar 依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring 上下文环境 支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- java mail 坐标依赖 -->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4.7</version>
</dependency>
</dependencies>
2.配置文件配置邮件发送 bean
<?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="mailSender"
class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.163.com" />
<property name="port" value="25" />
<property name="defaultEncoding" value="utf-8"></property>
<property name="username" value="[email protected]"></property>
<property name="password" value="1qaz2wsx"></property>
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
<!-- this is a template message that we can pre-load with default state -->
<bean id="templateMessage"
class="org.springframework.mail.SimpleMailMessage">
<property name="from" value="[email protected]" />
<property name="subject" value="spring_mail" />
</bean>
<bean id="orderManager" class="com.shsxt.test.SimpleOrderManager">
<property name="mailSender" ref="mailSender" />
<property name="templateMessage" ref="templateMessage" />
</bean>
</beans>
3.发送接口定义与实现
/**
* 发送邮件接口定义
* @author lp
*
*/
public interface OrderManager {
void placeOrder();
}
package com.shsxt.test;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
public class SimpleOrderManager implements OrderManager {
private MailSender mailSender;
private SimpleMailMessage templateMessage;
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
public void setTemplateMessage(SimpleMailMessage templateMessage) {
this.templateMessage = templateMessage;
}
public void placeOrder() {
SimpleMailMessage msg = new SimpleMailMessage(this.templateMessage);
msg.setTo("[email protected]");
msg.setText("test...asdasdasdsd");
try{
this.mailSender.send(msg);
}
catch (MailException ex) {
System.err.println(ex.getMessage());
}
}
}
测试
public class TestMail {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
OrderManager orderManager= (OrderManager) ac.getBean("orderManager");
orderManager.placeOrder();
}
}
18 spring 整合 jdbc
1.坐标添加
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring 测试环境 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.2.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- spring 框架坐标依赖添加 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- aop -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<!-- mysql 驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!-- c3p0 连接池 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- spring jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
<!-- spring 事物 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.2.RELEASE</version>
</dependency>
2.配置文件
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_jdbc?useUnicode=true&characterEncod
ing=utf8
jdbc.user=root
jdbc.password=123456
//可选
initialPoolSize=20
maxPoolSize=100
minPoolSize=10
maxIdleTime=600
acquireIncrement=5
maxStatements=5
idleConnectionTestPeriod=60
3.bean.xml配置修改
加载properties文件配置
<!-- 加载 properties 配置文件 -->
<context:property-placeholder location="db.properties" />
4.配置数据源
DBCP(DataBase connection pool),数据库连接池。 没有自动回收空闲连接的功能
C3P0 是一个开源的 JDBC 连接池 c3p0 有自动回收空闲连接功能
<!-- 配置 c3p0 数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
C3P0 其他额外配置(对应的值在 db.properties 文件中指定)
<!-- 指定连接池中保留的最大连接数. Default:15-->
<property name="maxPoolSize" value="${maxPoolSize}"/>
<!-- 指定连接池中保留的最小连接数-->
<property name="minPoolSize" value="${minPoolSize}"/>
<!-- 指定连接池的初始化连接数 取值应在 minPoolSize 与 maxPoolSize 之
间.Default:3-->
<property name="initialPoolSize" value="${initialPoolSize}"/>
<!-- 最大空闲时间,60 秒内未使用则连接被丢弃。若为 0 则永不丢弃。 Default:0-->
<property name="maxIdleTime" value="${maxIdleTime}"/>
<!-- 当连接池中的连接耗尽的时候 c3p0 一次同时获取的连接数. Default:3-->
<property name="acquireIncrement" value="${acquireIncrement}"/>
<!-- JDBC 的标准,用以控制数据源内加载的 PreparedStatements 数量。
但由于预缓存的 statements 属于单个 connection 而不是整个连接池所以设置这个参数需
要考虑到多方面的因数.如果 maxStatements 与 maxStatementsPerConnection 均为 0,则缓
存被关闭。Default:0-->
<property name="maxStatements" value="${maxStatements}"/>
<!-- 每 60 秒检查所有连接池中的空闲连接.Default:0 -->
<property name="idleConnectionTestPeriod" value="${idleConnectionTestPeriod}"/>
对于 dbcp 数据源配置如下:
<!-- 配置 dbcp 数据源-->
<bean id="myDataSource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${driver}" />
<property name="url" value="${url}"/>
<property name="username" value="${user}"/>
<property name="password" value="${password}"/>
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="1"/>
<!-- 最大空闲值.当经过一个高峰时间后,连接池可以慢慢将已经用不到的连接慢慢
释放一部分,一直减少到 maxIdle 为止 -->
<property name="maxIdle" value="2"/>
<!-- 最小空闲值.当空闲的连接数少于阀值时,连接池就会预申请一些连接,以避免
洪峰来时再申请而造成的性能开销 -->
<property name="minIdle" value="1"/>
</bean>
5.模板类配置
Spring 把 JDBC 中重复的操作建立成了一个模板类:org.springframework.jdbc.core.JdbcTemplate ,配置文件中加入
<!-- jdbcTemplate 配置 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
6.测试
创建数据库 spring_jdbc 并创建测试表 account
7.测试整合结果
通过 junit 测试 jdbcTemplate bean 是否获取到
public class TestSpringJdbc {
private JdbcTemplate jdbcTemplate;
@Before
public void init(){
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
jdbcTemplate=(JdbcTemplate) ctx.getBean("jdbcTemplate");
}
@Test
public void test() {
String sql="select count(1) from account";
Integer total= jdbcTemplate.queryForObject(sql, Integer.class);
System.out.println("总计路数:"+total);
}
}
19. Spring Jdbc 事务管理配置
xml 事务配置声明
1.修改 xml 命名空间
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
2.aop 代理
<aop:aspectj-autoproxy /><!-- aop -->
3.配置事物管理器
<!-- 事务管理器定义 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
4.配置事物相关通知
一般来说增删改方法 propagation=Required,对于查询方法使用 read-only=“true”
<!-- 配置通知 -->
<!--
tx:method 的属性:
* name 是必须的,表示与事务属性关联的方法名(业务方法名),对切入点进行细化。通配
符(*)可以用来指定一批关联到相同的事务属性的方法。
如:'get*'、'handle*'、'on*Event'等等.
propagation 不是必须的 ,默认值是 REQUIRED
表示事务传播行为, 包括
REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
isolation 不是必须的 默认值 DEFAULT
表示事务隔离级别(数据库的隔离级别)
timeout 不是必须的 默认值-1(永不超时)
表示事务超时的时间(以秒为单位)
read-only 不是必须的 默认值 false 不是只读的
表示事务是否只读
rollback-for 不是必须的
表示将被触发进行回滚的 Exception(s);以逗号分开。
如:'com.foo.MyBusinessException,ServletException'
no-rollback-for 不是必须的
表示不被触发进行回滚的 Exception(s);以逗号分开。
如:'com.foo.MyBusinessException,ServletException' 任何 RuntimeException 将触发事务回滚
-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!--匹配以 save 开头的 service 方法均加入事物-->
<tx:method name="save*" propagation="REQUIRED" />
<!—匹配以 del 开头的 service 方法均加入事物-->
<tx:method name="del*" propagation="REQUIRED" />
<!—匹配以 update 开头的 service 方法均加入事物-->
<tx:method name="update*" propagation="REQUIRED" />
<!—匹配以 query 开头的 service 方法事物为只读模式-->
<tx:method name="query*" read-only="true" />
</tx:attributes>
</tx:advice>
5.配置 aop(切入点、通知)
<!-- aop 切面定义 -->
<aop:config>
<aop:pointcut expression="execution( *
com.shsxt.service..*.*(..) )" id="cut" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="cut" />
</aop:config>
Spring 事务管理注解方式
1.配置事物管理器
<!-- spring 注解式事务声明 -->
<!-- 事务管理器定义 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
2.配置注解支持
<tx:annotation-driven transaction-manager="txManager"/>
3.Service 方法上在需要添加事务的方法上加入事物注解
@Override
@Transactional(propagation=Propagation.REQUIRED)
public void saveUser(String userName,String userPwd){
User user1=new User();
user1.setUserName(userName);
user1.setUserPwd(userPwd);
userDao.saveUser(user1);
userDao.delUserById(2);
}
备注:默认 spring 事务只在发生未被捕获的 runtimeexcetpion 时才回滚.spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样 aop 代理才能捕获到方法的异常,才能进行回滚,默认情况下 aop 只捕获runtimeexception 的异常,但可以通过配置来捕获特定的异常并回滚 换句话说在 service 的方法中不使用 try catch 或者在 catch 中最后加上 throw newRunTimeexcetpion(),这样程序异常时才能被 aop 捕获进而回滚
20.远程方法调用RMI
Java RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种机制,能够让在某个 Java 虚拟机上的对象调用另一个 Java 虚拟机中的对象上的方法。JVM 可以位于相同或不同计算机上,在多个 JVM 中,一个 JVM 可以调用存储在其它 JVM 的对象的方法。
RMI 实现常用 API
1).Remote 接口:每一个要暴露出去的 java 类,都需要实现 Remote 接口,并且所有
的方法必须抛出 RemoteException
2).UnicastRemoteObject 类:服务端程序的实现方案之一就是继承这个类,无参构造器
也要抛出 RemoteException
3).LocateRegistry 类创建能在特定接口接受调用远程对象注册服务程序。
4).Naming 类提供了存储和获得远程对象注册服务程序中的远程对象进行引用的方法
JAVA RMI实例
服务器端:
1.接口定义
package com.shsxt.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
/**
* 1.接口继承 Remote
* 2.对外服务方法声明 RemoteException 异常
*
*/
public interface IHelloService extends Remote{
public String sayHello(String msg) throws RemoteException;
}
2.接口具体服务实现类:
package com.shsxt.service.impl;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import com.shsxt.service.IHelloService;
/**
* 1、继承 UnicastRemoteObject
* 2、提供 无参构造 对外声明 RemoteException
*
*/
public class HelloServiceImpl extends UnicastRemoteObject implements IHelloService {
private static final long serialVersionUID = -5672932066566630040L;
public HelloServiceImpl() throws RemoteException {
}
@Override
public String sayHello(String msg) throws RemoteException{
System.out.println("服务器端接收到消息:"+msg);
return "hello:"+msg;
}
}
3.发布服务,对外提供相应服务
package com.shsxt.test;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import com.shsxt.service.impl.HelloServiceImpl;
public class Publish {
public static void main(String[] args) throws RemoteException,MalformedURLException, AlreadyBoundException {
//注册端口
LocateRegistry.createRegistry(8888);
//对外发布 rmi 服务
Naming.bind("rmi://127.0.0.1:8888/hello", new HelloServiceImpl());
}
}
客户端:
1.客户端与服务端声明相同接口
package com.shsxt.service;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IHelloService extends Remote{
public String sayHello(String msg) throws RemoteException;
}
2.客户端查找并调用远程服务
package com.shsxt.test;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import com.shsxt.service.IHelloService;
public class Test {
public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {
IHelloService helloService=(IHelloService) Naming.lookup("rmi://127.0.0.1:8888/hello");
System.out.println(helloService.sayHello("im win10"));
}
}
Spring实现远程方法调用
使用 spring 的 RMI,提供的服务简单方便,不用继承接口 和指定的类,不用抛出异常
服务端接口声明
package com.shsxt.service;
public interface IHelloService {
public String sayHello(String msg);
}
1.接口实现
package com.shsxt.service.impl;
import org.springframework.stereotype.Service;
import com.shsxt.service.IHelloService;
@Service
public class HelloServiceImpl implements IHelloService {
@Override
public String sayHello(String msg) {
System.out.println("服务器端收到信息:"+msg);
return "hello:"+msg;
}
}
2.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: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/springcontext.xsd">
<!-- 定义扫描范围 -->
<context:component-scan basepackage="com.shsxt"></context:component-scan>
<!-- 加入 rmi 相关配置 -->
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="hello"></property>
<property name="service" ref="helloServiceImpl"></property>
<property name="serviceInterface"
value="com.shsxt.service.IHelloService"></property>
<property name="registryPort" value="1199"></property>
</bean>
</beans>
3.对外发布远程服务
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class Publist {
public static void main(String[] args) {
/**
* 启动 spring ioc 容器 ,并发布对应服务
*/
ApplicationContext ac=new
ClassPathXmlApplicationContext("beans.xml");
}
}
客户端调用
1.接口声明
package com.shsxt.service;
public interface IHelloService {
public String sayHello(String msg);
}
2.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: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/springcontext.xsd">
<!-- 定义扫描范围 -->
<context:component-scan basepackage="com.shsxt"></context:component-scan>
<bean class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl"
value="rmi://localhost:1199/hello"></property>
<property name="serviceInterface"
value="com.shsxt.service.IHelloService"></property>
</bean>
</beans>
3.客户端使用远程接口方法服务
package com.shsxt.service.impl;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import com.shsxt.service.IHelloService;
@Service
public class UserServiceImpl {
@Resource
private IHelloService helloService;
public void test(){
System.out.println(helloService.sayHello("im win10"));
}
}
4.客户端测试
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
import com.shsxt.service.IHelloService;
import com.shsxt.service.impl.UserServiceImpl;
public class Test {
public static void main(String[] args) {
ApplicationContext ac=new
ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userServiceImpl= (UserServiceImpl)
ac.getBean("userServiceImpl");
userServiceImpl.test();
}
}
上一篇: 一步一步搭建k8s
下一篇: react组件有什么缺点