IOC(Inversion Of Controller)又称控制反转,是一种通过(xml或者注解)并通过第三方生成或获取特定对象的方式,在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI:Dependency Injection)
总结:所谓的控制反转,就是创建对象的方式反转了,总的来说,对象可以交给Spring容器进行创建,管理,装配
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.7.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
<dependency>
<groupId>javax.annotationgroupId>
<artifactId>javax.annotation-apiartifactId>
<version>1.3.2version>
dependency>
@Component:组件,使用此注解声明当前Java类交由Spring进行管理(在此注解的基础上还增加了三个衍生注解,基于MVC三层架构)
注意事项:翻阅底层源码可以发现这四个注解的代码都是一样的,意味着他们的功能都是一样的,都是代表将某个类交由Spring托管,进行Bean的装配
对于xml和注解:
所以针对这种情况最直接的解决方案就是两种方式进行组合(最佳实现)
<context:component-scan base-package="com.hrc"/>
<context:annotation-config/>
SpringAOP(Aspect Oriented Programming)的底层就是代理设计模式!!!
代理模式有两种:静态代理和动态代理
业务分析:
// 以租房为例实现静态代理
public interface Rent {
void rent();
}
// 房东
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子(真实业务)");
}
}
public class MiddleProxy extends Host {
// 处理真实业务
public void rent() {
this.rentBefore();
super.rent(); // 真实业务
this.rentAfter();
this.res();
}
// 实现扩展业务
public void rentBefore() {
System.out.println("中介接单");
}
public void rentAfter() {
System.out.println("中间商赚差价");
}
public void res() {
System.out.println("扩展业务完成");
}
}
public class Client {
public static void main(String[] args) {
// 代理角色,中介帮房东租房子,但是中介会做一些房东不会做的扩展业务
MiddleProxy proxy = new MiddleProxy();
proxy.rent();
}
}
代理模式的好处:
缺点:
业务分析:
抽象角色:与静态代理相同
代理角色:动态生成,不是由开发者自己编写,而是开发者自定义一个模板然后交给程序去生成代理对象
动态代理的实现机制有两种:一种是基于接口的动态代理,还有一种就是基于cglib实现动态代理
首先需要熟悉两个Java类:Proxy:代理;InvocationHandler:调用处理程序
动态代理的好处:
优化之前实现的房东买房子的业务操作
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 用此类动态生成代理类
public class ProxyInvocationHandler implements InvocationHandler {
// 在生成代理类的同时还需要一个被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 生成代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
/**
* 处理代理实例,并返回结果
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
// 动态代理的本质就是使用反射机制实现
Object res = method.invoke(target, args);
return res;
}
public void log(String msg) {
System.out.println("【INFO】" + msg);
}
}
public class Client {
public static void main(String[] args) {
// 真实业务主题
Host host = new Host();
// 生成代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(host); // 设置代理对象
// 动态生成代理类
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
AOP(Aspect Oriented Programming),意思是面向切面编程,它是OOP(Object-Oriented Programming 面向对象编程)的一种延续
在不破坏原有代码实现的基础上,利用“织入”的模式来实现一些代码的动态配置
利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高代码可重用性,提高开发效率
使用SpringAOP需要额外导入相关依赖
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.5version>
dependency>
主要是通过实现Spring的接口来进行切面的处理
public interface UserService {
void insert();
void delete();
void update();
void select();
}
/*--------------两个类分开写----------------*/
public class UserServiceImpl implements UserService {
@Override
public void insert() {
System.out.println("【INSERT】增加了一个用户");
}
@Override
public void delete() {
System.out.println("【DELETE】删除了一个用户");
}
@Override
public void update() {
System.out.println("【UPDATE】修改了一个用户");
}
@Override
public void select() {
System.out.println("【SELECT】查询了一个用户");
}
}
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
/**
* 在实现操作业务之前首先要先做一些日志信息
* @param method 要执行的目标对象的方法
* @param objects 参数,对象数组
* @param target 目标对象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] objects, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "被执行了");
}
}
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
// 后置通知,并且接收返回值
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了" + method.getName() + "方法,返回结果为" + returnValue);
}
}
<bean id="userService" class="com.hrc.service.UserServiceImpl"/>
<bean id="log" class="com.hrc.log.Log"/>
<bean id="afterLog" class="com.hrc.log.AfterLog"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(public * com.hrc.service..*(..))"/>
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
aop:config>
这里有一个小东西叫做AspectJ表达式,Spring容器中支持此表达式,用来进行切入点的定义
其语法格式为:方法注解 权限修饰符 返回值 全限定类名 方法名 (参数);这里有几个地方需要注意
import com.hrc.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 动态代理代理的是接口,实现类不需要被代理
UserService service = context.getBean("userService", UserService.class);
service.insert();
}
}
自定义类实现AOP只需要编写自定义类,无需实现Spring自带的接口,通过配置文件进行切面的处理配置
public class MyselfClass {
public void before() {
System.out.println("【INFO---BEFORE】业务处理之前");
}
public void after() {
System.out.println("【INFO---AFTER】业务处理之后");
}
}
<bean id="myselfClass" class="com.hrc.myClass.MyselfClass"/>
<aop:config>
<aop:aspect ref="myselfClass">
<aop:pointcut id="pointcut" expression="execution(public * com.hrc.service..*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
aop:aspect>
aop:config>
// 使用注解方式实现AOP
@Aspect // 标注此类为一个切面
public class AnnotationPointcut {
@Before("execution(public * com.hrc.service..*(..))")
public void before() {
System.out.println("【INFO】方法执行前");
}
@After("execution(public * com.hrc.service..*(..))")
public void after() {
System.out.println("【INFO】方法执行后");
}
// 在环绕增强中,可以给定一个参数,代表我们要获取的切入的点
@Around("execution(public * com.hrc.service..*(..))")
public void around(ProceedingJoinPoint pj) throws Throwable {
System.out.println("【INFO】使用环绕之前");
System.out.println("【INFO】获得签名:" + pj.getSignature());
// 执行此方法
Object proceed = pj.proceed();
System.out.println("【INFO】获得执行对象:" + proceed);
System.out.println("【INFO】使用环绕之后");
}
}
<bean id="annotationPointcut" class="com.hrc.myClass.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
实现步骤
相关依赖
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>5.2.7.RELEASEversion>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.5version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
<version>5.2.7.RELEASEversion>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatis-springartifactId>
<version>2.0.5version>
dependency>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath*:com.hrc.mapper/UserMapper.xml"/>
bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
import com.hrc.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> getUsers();
}
import com.hrc.mapper.UserMapper;
import com.hrc.pojo.User;
import org.mybatis.spring.SqlSessionTemplate;
import java.util.List;
public class UserMapperImpl implements UserMapper {
// 在以前都使用SqlSession来执行所有操作,现在只需要使用SqlSessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> getUsers() {
return sqlSession.getMapper(UserMapper.class).getUsers();
}
}
import com.hrc.mapper.UserMapper;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper mapper = context.getBean("userMapper", UserMapper.class);
mapper.getUsers().forEach(System.out::println);
}
}
Spring-MyBatis还有一种整合方式,就是直接实现SqlSessionDaoSupport类
<bean id="mapper" class="com.hrc.mapper.impl.UserMapperImplement">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
import com.hrc.mapper.UserMapper;
import com.hrc.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;
public class UserMapperImplement extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> getUsers() {
// 由于继承了SqlSessionDaoSupport类,可以直接使用getSqlSession方法得到进一步简化
return getSqlSession().getMapper(UserMapper.class).getUsers();
}
}
事务的ACID原则
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:advice id="interceptor" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="addUser" propagation="REQUIRED" isolation="DEFAULT"/>
<tx:method name="selectUsers"/>
<tx:method name="delUser" propagation="REQUIRED"/>
<tx:method name="*" propagation="REQUIRED"/>
tx:attributes>
tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(public * com.hrc.mapper..*.*(..))"/>
<aop:advisor advice-ref="interceptor" pointcut-ref="txPointcut"/>
aop:config>
为什么需要事务
刚刚在使用xml进行事务的织入时有一个标签叫做propagation,propagation在xml中可以进行事务的传播属性的处理配置,它主要有以下几种属性
(面试可能会问到,建议最好还是记一下)