ssm框架重点
1.初识spring
1.1spring优点
- spring是一个轻量级(小内存)、非入侵式(对现有代码没有影响)的开源免费框架(容器)
- 控制反转(IOC),面向切面编程(AOP)是两个特点
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency>
1.2spring拓展
1.3Ioc思想
- 三层架构中(controller,service,dao),用户实际调用业务层(servive),通过业务层去调用dao层。而且接口中只存放方法,在类中要重写接口中的具体方法。
所以 接口类 接口名 = new 实现类;eg: UserService userService = new UserServiceImpl(); - 因此我们每次想要实现某一方法时,就得在serviceImpl中修改userService的实现类,这是很麻烦的。
- 引入set进行动态对象的注入
- 测试类中
前后思想转变主要在于主动性变成了用户决定(控制反转使得对象的创建转移给了第三方)
在spring中实现这一思想的是IOC容器,其实现方式是通过依赖注入(DI)
1.4控制反转(重点)
控制:即谁来控制对象的创建,spring中主要由spring自己创建
反转:程序不主动创建对象,而是被动的接受对象
依赖注入:其根本就是引用set方法
2.HelloSpring
2.1xml(重要)
最终实现业务层代码中不需要我们去新建对象,直接将对象交给spring容器去创建
即我们只需要在Rsource下创建xml文件,并在其中加入bean对象,这样更易于配置,大大降低了代码的耦合度
注意:id只是变量名(对象名),关键是看其后面new 出来的类
property标签即可以理解为引用set方法给属性赋值,该值分为具体值或者一个对象(该对象若是spring管理,则就是其id)
name是类中的某一属性,ref/value二者根据情况选择,ref后面是类,value则是值
2.2MyTest
2.3spring配置
2.3.1bean的配置
<?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">
</beans>
2.3.2import
3.依赖注入(DI)
依赖:依赖spring容器生成bean对象
注入:利用property标签给某个类的属性赋值
3.1构造器注入
3.2set方法注入(重点)
特别关注map注入是在entry标签给键值对赋值
property注入是在props下的prop标签内注入键,而值是在prop标签中间
<bean id="address" class="com.itheima.pojo.Address" >
<property name="address" value="上海" ></property>
</bean>
<bean id="student" class="com.itheima.pojo.Student">
<!-- 普通注入-->
<property name="name" value="lyk"></property>
<!--bean注入-->
<property name="address" ref="address"></property>
<!--数组注入-->
<property name="books">
<array>
<value>水浒传</value>
<value>西游记</value>
<value>红楼梦</value>
</array>
</property>
<!--list注入-->
<property name="hobbys">
<list>
<value>singing</value>
<value>music</value>
</list>
</property>
<!--map注入-->
<property name="card">
<map>
<entry key="手机" value="1234566666"></entry>
<entry key="身份证" value="123456622323666"></entry>
</map>
</property>
<!--set注入-->
<property name="games">
<set>
<value>lol</value>
<value>bob</value>
</set>
</property>
<!--null注入-->
<property name="wife"><null/></property>
<!--properties注入-->
<property name="info" >
<props>
<prop key="id">211110173</prop>
<prop key="sex">boy</prop>
<prop key="name">mls</prop>
</props>
</property>
</bean>
3.3拓展方式注入
以下两个注入都需要引入第三方配置,而且c命名注入是基于构造器注入,因此在类中需要有无参/有参构造
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbean.xml");
User user = context.getBean("user", User.class);
System.out.println(user.toString());
}
3.3.1p(property)命名注入
3.3.2c(constructor)命名注入
4.bean作用域
4.1Singleton
单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象
4.2prototype
Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。
4.3request
当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;每个HTTP请求都会有各自的bean实例.
4.4session
5.自动装配(重要)
两个条件:
-
组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
-
自动装配(autowiring):spring自动满足bean之间的依赖
5.1bean的自动装配
5.2注解的自动装配(重要)
1.配置注解的支持<context:annotation-config/>
使用注解之后,类中的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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
2.@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。
@Qualifier则可以根据byName的方式自动装配,不能单独使用
@Resource先进行byName查找,失败;再进行byType查找,成功
总结:
1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
6.java配置spring
即用配置类config代替xml文件
6.1配置类
6.2用例类
6.3测试类
注意这里的Annotationconfig上下文来获取容器,而且括号内可以直接加入配置类名称,而不需要双引号
7.代理模式
Aop思想:在不改变原代码的情况下,实现了对原有功能的增强
7.1静态代理
7.1.1角色分工
-
抽象角色 : 一般使用接口或者抽象类来实现
-
真实角色 : 被代理的角色(实现类)
-
代理角色(proxy) : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 ,而且也要实现抽象类,在里面还要有实现类对象,并且带有set方法。
-
客户 : 使用代理角色来进行一些操作 .
//1、创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!
//抽象角色:增删改查业务
public interface UserService {
void add();
void delete();
void update();
void query();
}
2、我们需要一个真实对象来完成这些增删改查操作
//真实对象,完成增删改查操作的人
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
3、需求来了,现在我们需要增加一个日志功能,怎么实现!
思路1 :在实现类上增加代码 【麻烦!】
思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!
4、设置一个代理类来处理日志!代理角色
//代理角色,在这里面增加日志的实现
public class UserServiceProxy implements UserService {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
5、测试访问类:
public class Client {
public static void main(String[] args) {
//真实业务
UserServiceImpl userService = new UserServiceImpl();
//代理类
UserServiceProxy proxy = new UserServiceProxy();
//使用代理类实现日志功能!
proxy.setUserService(userService);
proxy.add();
}
}
7.2动态代理(重点)
动态代理的实质是反射
动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
7.2.1proxy类
生成代理类
7.2.2invocationHandler类
这个相当于工具类,实际上就是自动生成代理类,只需要修改相对应的接口,还有就是处理代理实例
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);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String msg){
System.out.println("执行了"+msg+"方法");
}
}
测试类
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色,不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);//设置要代理的对象
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.add();
}
}
8.AOP
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术,使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性。
aop有七大属性
-
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
-
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
-
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
-
目标(Target):被通知对象。
-
代理(Proxy):向目标对象应用通知之后创建的对象。
-
切入点(PointCut):切面通知 执行的 “地点”的定义。
-
连接点(JointPoint):与切入点匹配的执行点。
使用前需要导入依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
8.1使用spring实现aop(接口)
编写基本的接口和实现类,然后去写我们的增强类 , 我们编写两个 , 一个前置增强 一个后置增强
public class Log implements MethodBeforeAdvice { //method : 要执行的目标对象的方法 //objects : 被调用的方法的参数 //Object : 目标对象 @Override public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被执行了"); } }
public class AfterLog implements AfterReturningAdvice { //returnValue 返回值 //method被调用的方法 //args 被调用的方法的对象的参数 //target 被调用的目标对象 @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("执行了" + target.getClass().getName() +"的"+method.getName()+"方法," +"返回值:"+returnValue); } }
最后去spring的文件中注册 , 并实现aop切入实现
<!--注册bean--> <bean id="userService" class="com.kuang.service.UserServiceImpl"/> <bean id="log" class="com.kuang.log.Log"/> <bean id="afterLog" class="com.kuang.log.AfterLog"/> <!--aop的配置--> <aop:config> <!--切入点 expression:表达式匹配要执行的方法--> <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/> <!--执行环绕; advice-ref执行方法 . pointcut-ref切入点--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config> </beans>
8.2 自定义类实现aop
编写自定义类
public class DiyPointcut {
public void before(){
System.out.println("---------方法执行前---------");
}
public void after(){
System.out.println("---------方法执行后---------");
}
}
MyTest
8.3注解实现aop
编写一个注解实现的代码增强类
@Aspect //切面类
public class before {
@Before("execution(* com.itheima.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* com.itheima.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
@Around("execution(* com.itheima.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Signature signature = jp.getSignature();
System.out.println("signature"+signature);
Object proceed = jp.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
在Spring配置文件中,注册bean,并增加支持注解的配置
<!--第三种方式:注解实现-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
9.整合mybatis
1.导入jar包
junit,mybatis,mysql,spring,aop(aspect),mybatis-spring
2.编写配置文件
即在resource下新建mybatis-config.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.itheima.pojo"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
</dataSource>
</environment>
</environments>
<!-- <mappers>-->
<!-- <mapper resource="com/example/mappers/UserMapper.xml"/>-->
<!-- </mappers>-->
</configuration>
3.编写mapper接口
public interface UserMapper {
public List<User> selectUser();
}
4.编写mapper.xml(注意要在同一目录下)
可以在xml文件基础上修改,只需要将configuration,config这些修改为mapper
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.Usermapper">
<Select id="selectUser" resulType="user">
select * from mybatis.user;
</Select>
</mapper>
5.测试
9.1mybatis-spring
需要加入usermapperimpl
简化