近几年,技术市场对新人越来越不友好,社招几乎是三年经验起步。所以很多人都说能走校招千万别走社招,年初我企图走社招,然后绝望了 = =。还是要抓紧每一秒,多学习多练习。
这里介绍的是 Spring Framework。
根据需要选择手动导入 jar 包,或者用依赖管理工具。
dependencies {
// 核心包
compile 'org.springframework:spring-context:4.3.8.RELEASE'
// 可选包
compile 'org.springframework:spring-tx:4.3.8.RELEASE'
compile 'org.springframework:spring-web:4.3.8.RELEASE'
compile 'org.springframework:spring-orm:4.3.8.RELEASE'
compile 'org.springframework:spring-aspects:4.3.8.RELEASE'
compile 'org.springframework:spring-test:4.3.8.RELEASE'
}复制代码
列举了一些常用的,更多详情参考 官网定义
控制反转(Inverse of Control):对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。
这里是指将对象创建的任务交给 Spring 来做。
Demo
com/ittianyu/spring/a_ioc/applicationContext.xml
复制代码
com.ittianyu.spring.a_base.a_ioc.TestClass
public class TestClass {
@Test
public void helloIOC() {
String xmlPath = "com/ittianyu/spring/a_ioc/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 通过 spring 创建 dao
UserDao userDao = (UserDao) applicationContext.getBean("UserDao");
userDao.save(new User("hello spring !"));
}
}复制代码
定义
依赖注入(Dependency Injection,简称DI):在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。
在这里指的是 要创建的对象中的成员变量由 Spring 进行 set。
Demo
com/ittianyu/spring/b_di/applicationContext.xml
复制代码
com.ittianyu.spring.a_base.b_di.TestClass
public class TestClass {
@Test
public void helloDI() {
String xmlPath = "com/ittianyu/spring/b_di/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 通过 spring 创建 service
UserService userService = (UserService) applicationContext.getBean("UserService");
userService.addUser(new User("hello spring !"));
}
}复制代码
默认构造、静态工厂、实例工厂
默认构造
通过默认构造方法实例化对象
复制代码
静态工厂
通过工厂的静态方法实例化对象
复制代码
工厂
通过工厂的普通方法实例化对象
复制代码
getObject()
用于获得特定 bean。
FB fb = new FB();
return fb.getObject();复制代码
类别 | 说明 |
---|---|
singleton | Spring IOC 容器中仅存在一份 bean 实例 |
prototype | 每次都创建新的实例 |
request | 一次 http 请求创建一个新的 bean,仅适用于 WebApplicationContext |
session | 一个 session 对应一个 bean 实例,仅适用于 WebApplicationContext |
globalSession | 一般用于 Portlet 应用环境,作用域仅适用于 WebApplicationContext 环境 |
scope 为作用域
复制代码
初始化和销毁
目标方法执行前后执行的方法
复制代码
例子:
com.ittianyu.spring.a_base.e_lifecycle.UserServiceImpl
public class UserServiceImpl implements UserService{
@Override
public void addUser() {
System.out.println("addUser");
}
// 在 xml 中配置声明周期方法
public void onInit() {
System.out.println("onInit");
}
// 销毁方法只有满足 1.容器 close 2. 必须是单例
public void onDestroy() {
System.out.println("onDestroy");
}
}复制代码
配置:
com/ittianyu/spring/a_base/e_lifecycle/applicationContext.xml
...
...复制代码
测试:
com.ittianyu.spring.a_base.e_lifecycle.TestClass
public class TestClass {
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/e_lifecycle/applicationContext.xml";
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
// 通过 spring 生成工厂 调用 工厂方法 生成对象
UserService userService = applicationContext.getBean("UserService", UserService.class);
userService.addUser();
// 关闭容器才会调用 销毁的方法
applicationContext.close();
}
}复制代码
BeanPostProcessor
只要实现此接口BeanPostProcessor,并配置此 bean,则在所有初始化方法前执行 before()
,在初始化方法之后执行 after()
。
例子:
com.ittianyu.spring.a_base.e_lifecycle.MyBeanPostProcessor
public class MyBeanPostProcessor implements BeanPostProcessor {
// 不在 before 使用代理因为 jdk 的代理是面向接口,而 init 和 destroy 方法是 实现类的
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("before");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("after");
// 在 after 中生成 代理对象,在执行方法前后开启和关闭事务
Object proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始事务");
Object result = method.invoke(bean, args);
System.out.println("关闭事务");
return result;
}
});
return proxy;
}
}复制代码
com/ittianyu/spring/a_base/e_lifecycle/applicationContext.xml
...
...复制代码
注入方式
构造注入
实体类
public class User {
private Integer id;
private String username;
private Integer age;
public User(Integer id, String username) {
this.id = id;
this.username = username;
}
// 省略 get set...
}复制代码
配置
...
...复制代码
set 注入
实体类省略
...
18
...复制代码
P
对 "set 注入" 简化,使用:
复制代码
替换
复制代码
必须添加 p 命名空间
复制代码
例子:
...
...复制代码
SpEL
对
进行统一编程,所有的内容都使用 value
#{123}、#{'jack'}: 数字、字符串
#{beanId}:另一个bean引用
#{beanId.propName}:操作数据
#{beanId.toString()}:执行方法
#{T(类).字段|方法}:静态方法或字段复制代码
例子:
复制代码
集合注入
1
2
3
l1
l2
l3
s1
s2
s3
p1
p2
p3
复制代码
类型
@Component
取代
@Component("id")
取代
@Component
衍生注解(功能一样)取代
@Value("")
@Autowired
@Autowired
@Qualifier("名称")
@Resource("名称")
@PostConstruct
@PreDestroy
@Scope("prototype")
配置
需要配置自动扫描才能使注解生效
复制代码
定义
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
优点
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
原理
aop底层将采用代理机制进行实现。
术语
APO 联盟通知类型
AOP联盟为通知 Advice 定义了 org.aopalliance.aop.Advice
Spring按照通知 Advice 在目标类方法的连接点位置,可以分为5类
org.springframework.aop.MethodBeforeAdvice
org.springframework.aop.AfterReturningAdvice
org.aopalliance.intercept.MethodInterceptor
org.springframework.aop.ThrowsAdvice
org.springframework.aop.IntroductionInterceptor
切面类
采用环绕通知
public class SpringTimeSpaceAspect implements Aspect, MethodInterceptor {
private long beforeTime;
@Override
public void before() {
beforeTime = System.currentTimeMillis();
System.out.println("before:" + beforeTime);
}
@Override
public void after() {
long afterTime = System.currentTimeMillis();
System.out.println("after:" + afterTime);
System.out.println("space:" + (afterTime - beforeTime));
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
before();
Object result = invocation.proceed();
after();
return result;
}
}复制代码
配置
进行配置 proxy-target-class="true" true 表示底层使用 cglib 代理
切入点, 从目标对象获得具体方法
特殊的切面,只有一个通知 和 一个切入点
advice-ref 通知引用
pointcut-ref 切入点引用复制代码
execution(* com.ittianyu.c_spring_aop.*.*(..))
选择方法 返回值任意 包 类名任意 方法名任意 参数任意复制代码
例如:
复制代码
介绍
@AspectJ
是 AspectJ1.5 新增功能,通过 JDK5 注解技术,允许直接在 Bean 类中定义切面切入点表达式
execution()
用于描述方法 【掌握】
语法:execution(修饰符 返回值 包.类.方法名(参数) throws异常)
public 公共方法
* 任意复制代码
void 返回没有值
String 返回值字符串
* 任意复制代码
com.ittianyu.crm 固定包
com.ittianyu.crm.*.service crm包下面子包任意 (例如:com.ittianyu.crm.staff.service)
com.ittianyu.crm.. crm包下面的所有子包(含自己)
com.ittianyu.crm.*.service.. crm包下面任意子包,固定目录service,service目录任意包复制代码
UserServiceImpl 指定类
*Impl 以Impl结尾
User* 以User开头
* 任意复制代码
addUser 固定方法
add* 以add开头
*Do 以Do结尾
* 任意复制代码
() 无参
(int) 一个整型
(int ,int) 两个
(..) 参数任意复制代码
throws ,可省略,一般不写。
综合1
execution(* com.ittianyu.crm.*.service..*.*(..))复制代码
复制代码
within(com.ittianyu.aop..*)复制代码
this(com.ittianyu.aop.user.UserDAO)复制代码
target(com.ittianyu.aop.user.UserDAO)复制代码
args(int,int)复制代码
bean('userServiceId')复制代码
通知类型
基于 xml Demo
实体类
public class MyAspect {
public void before(JoinPoint joinPoint) {
System.out.println("before:" + joinPoint.getSignature().getName());
}
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("after-returning:" + joinPoint.getSignature().getName() + ", result:" + result);
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around-before:" + joinPoint.getSignature().getName());
Object result = joinPoint.proceed();
System.out.println("around-after:" + joinPoint.getSignature().getName());
return result;
}
public void afterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("after-throwing:" + joinPoint.getSignature().getName() + ", exception:" + e.getMessage());
}
public void after(JoinPoint joinPoint) {
System.out.println("after:" + joinPoint.getSignature().getName());
}
}复制代码
配置
复制代码
测试
public class TestClass {
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/b_aop/d_aspect/a_xml/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("UserService");
userService.add();
userService.delete();
userService.update();
}
}复制代码
基于注解 Demo
实体类
@Component
@Aspect
public class MyAspect {
/**
*
*/
@Pointcut(value = "execution(* com.ittianyu.spring.b_aop.d_aspect.b_annotation.UserServiceImpl.*(..))")
public void myPointcut() {
}
@Before(value = "myPointcut()")
public void before(JoinPoint joinPoint) {
System.out.println("before:" + joinPoint.getSignature().getName());
}
@AfterReturning(value = "myPointcut()", returning = "result")
public void afterReturning(JoinPoint joinPoint, Object result) {
System.out.println("after-returning:" + joinPoint.getSignature().getName() + ", result:" + result);
}
@Around(value = "myPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around-before:" + joinPoint.getSignature().getName());
Object result = joinPoint.proceed();
System.out.println("around-after:" + joinPoint.getSignature().getName());
return result;
}
@AfterThrowing(value = "myPointcut()", throwing = "e")
public void afterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("after-throwing:" + joinPoint.getSignature().getName() + ", exception:" + e.getMessage());
}
@After(value = "myPointcut()")
public void after(JoinPoint joinPoint) {
System.out.println("after:" + joinPoint.getSignature().getName());
}
}复制代码
切面类
@Service("UserService")
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("add");
}
@Override
public String delete() {
System.out.println("delete");
// int a = 1 / 0;
return "result-delete";
}
@Override
public void update() {
System.out.println("update");
}
}复制代码
配置
复制代码
测试
public class TestClass {
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/b_aop/d_aspect/b_annotation/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("UserService");
userService.add();
userService.delete();
userService.update();
}
}复制代码
Spring 提供用于操作JDBC工具类,类似:DBUtils。
依赖 连接池DataSource (数据源)
可以通过代码来设置数据源,但一般都是通过配置文件来注入
//1 创建数据源(连接池) dbcp
BasicDataSource dataSource = new BasicDataSource();
// * 基本4项
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/spring_day02");
dataSource.setUsername("root");
dataSource.setPassword("1234");
//2 创建模板
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSource);
//3 通过api操作
jdbcTemplate.update("insert into t_user(username,password) values(?,?);", "tom","1");复制代码
复制代码
复制代码
properties 配置
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///myusers
jdbc.user=root
jdbc.password=123456复制代码
Spring 配置
复制代码
Dao 继承 JdbcDaoSupport 后,继承了设置数据源的方法。public final void setDataSource(DataSource dataSource)
然后自动创建 JdbcTemplate。
public class UserDao extends JdbcDaoSupport{
public void add(User user) {
String sql = "insert into user (username, password, nick) VALUES (?, ?, ?);";
Object[] args = new Object[]{user.getUsername(), user.getPassword(), user.getNick()};
getJdbcTemplate().update(sql, args);
}
}复制代码
所以,现在 Spring 配置只需要给 dao 注入数据源即可。
复制代码
Spring 中的事务有三个重要的接口。
常见的事务管理器
Api
事务状态
public interface TransactionStatus extends SavepointManager, Flushable {
/**
* 是否是新事务
*/
boolean isNewTransaction();
/**
* 是否有保存点
*/
boolean hasSavepoint();
/**
* 设置回滚
*/
void setRollbackOnly();
/**
* 是否回滚
*/
boolean isRollbackOnly();
/**
* 刷新
*/
@Override
void flush();
/**
* 是否已完成
*/
boolean isCompleted();
}复制代码
事务详情
public interface TransactionDefinition {
/**
* 传播行为
*/
int getPropagationBehavior();
/**
* 隔离级别
*/
int getIsolationLevel();
/**
* 超时时间
*/
int getTimeout();
/**
* 是否只读
*/
boolean isReadOnly();
/**
* 配置事务详情名称。一般方法名称。例如:save、add 等
*/
String getName();
}复制代码
传播行为
在两个业务之间如何共享事务。有以下取值:
常用的是:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED
表
create table account(
id int primary key auto_increment,
username varchar(50),
money int
);
insert into account(username,money) values('jack','10000');
insert into account(username,money) values('rose','10000');复制代码
Dao
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void out(String outer, Integer money) {
String sql = "UPDATE account SET money = money - ? WHERE username = ?";
Object[] args = new Object[]{money, outer};
getJdbcTemplate().update(sql, args);
}
@Override
public void in(String inner, Integer money) {
String sql = "UPDATE account SET money = money + ? WHERE username = ?";
Object[] args = new Object[]{money, inner};
getJdbcTemplate().update(sql, args);
}
}复制代码
Service
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
// int i = 1 / 0;
accountDao.in(inner, money);
}
}复制代码
xml 配置
复制代码
注解配置
Service 注解
@Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer, money);
// int i = 1 / 0;
accountDao.in(inner, money);
}
}复制代码
xml 配置
复制代码
测试
@Test
public void test() {
String xmlPath = "com/ittianyu/spring/d_tx/d_annotation/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
AccountService accountService = applicationContext.getBean("AccountService", AccountService.class);
accountService.transfer("zs", "ls", 100);
}复制代码
导包
需要导入 spring-test 包,环境搭建列表里面已经包含了。
目的
配置
@ContextConfiguration 用于指定配置的位置
@Autowired 指定需要注入的对象
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:com/ittianyu/spring/e_junit/applicationContext.xml")
public class TestClass {
@Autowired
private AccountService accountService;
@Test
public void test() {
accountService.transfer("zs", "ls", 100);
}
}复制代码
导包
需要导入 spring-web 包,环境搭建列表里面已经包含了。
配置
在 web.xml 中配置 spring listener
contextConfigLocation
classpath:com/ittianyu/spring/f_web/applicationContext.xml
org.springframework.web.context.ContextLoaderListener
复制代码
手动获取 Spring 容器
// 方式一,直接 map 中获取
ApplicationContext applicationContext1 = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
// 方式二,通过工具类获取
ApplicationContext applicationContext2 = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
AccountService accountService = applicationContext2.getBean("AccountService", AccountService.class);
accountService.transfer("zs", "ls", 100);复制代码
Struts2
特别注意 struts2-spring-plugin
,这个包是整合 spring 用的,导入后,Spring 可以自动根据名称把 service 注入到 action。
compile "org.apache.struts:struts2-core:2.5.10.1"
compile "org.apache.struts:struts2-convention-plugin:2.5.10"
compile "org.apache.struts:struts2-spring-plugin:2.5.10"复制代码
Spring
compile "org.springframework:spring-context:4.3.7.RELEASE"
compile "org.springframework:spring-tx:4.3.7.RELEASE"
compile 'org.springframework:spring-web:4.3.7.RELEASE'
compile 'org.springframework:spring-orm:4.3.7.RELEASE'
compile 'org.springframework:spring-aspects:4.3.7.RELEASE'
compile 'org.springframework:spring-test:4.3.7.RELEASE'复制代码
Hibernate
compile "org.hibernate:hibernate-core:5.2.9.Final"复制代码
其他
// servlet
providedCompile "javax.servlet:javax.servlet-api:3.0.1"
// mysql
compile 'mysql:mysql-connector-java:5.1.40'
// c3p0
compile 'com.mchange:c3p0:0.9.5.2'复制代码
不再使用 hibernate.cfg.xml,使用 Spring datasource 取代。
jdbc.roperties
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/ee19_crm
jdbc.user=root
jdbc.password=123456复制代码
applicationContext.xml
org.hibernate.dialect.MySQL57Dialect
true
true
update
jdbc:mysql://localhost:3306/ee19_crm
com.mysql.jdbc.Driver
classpath:com/ittianyu/crm/classes/bean/CrmClass.hbm.xml
classpath:com/ittianyu/crm/coursetype/bean/CrmCourseType.hbm.xml
classpath:com/ittianyu/crm/department/bean/CrmDepartment.hbm.xml
classpath:com/ittianyu/crm/post/bean/CrmPost.hbm.xml
classpath:com/ittianyu/crm/staff/bean/CrmStaff.hbm.xml
复制代码
Dao
Dao 继承 HibernateDaoSupport
public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
@Override
public void save(User user) {
this.getHibernateTemplate().save(user);
}
}复制代码
strut2 还是原来写法。
Spring 中配置 Service 时,bean 的 id 必须和 Action 类中 service 的 set名字一致。
比如:
配置
复制代码
StaffAction
public void setStaffService(StaffService staffService) {
this.staffService = staffService;
}
最后,最近整理了一套完整关于spring的学习文档,有需要的伙伴们,可以私信 ‘3’ !