Spring总结
Spring
SSH:Spring . Struts1/2 . Hiberernate
SSM:Spring . SpringMVC . Mybatis
Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
◆目的:解决企业应用开发的复杂性
◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
◆范围:任何Java应用
Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。
起源
要谈Spring的历史,就要先谈J2EE。J2EE应用程序的广泛实现是在1999年和2000年开始的,它的出现带来了诸如事务管理之类的核心中间层概念的标准化,但是在实践中并没有获得绝对的成功,因为开发效率,开发难度和实际的性能都令人失望。
曾经使用过EJB开发JAVA EE应用的人,一定知道,在EJB开始的学习和应用非常的艰苦,很多东西都不能一下子就很容易的理解。EJB要严格地实现各种不同类型的接口,类似的或者重复的代码大量存在。而配置也是复杂和单调,同样使用JNDI进行对象查找的代码也是单调而枯燥。虽然有一些开发工作随着xdoclet的出现,而有所缓解,但是学习EJB的高昂代价,和极低的开发效率,极高的资源消耗,都造成了EJB的使用困难。而Spring出现的初衷就是为了解决类似的这些问题。
Spring的一个最大的目的就是使JAVA EE开发更加容易。同时,Spring之所以与Struts、Hibernate等单层框架不同,是因为Spring致力于提供一个以统一的、高效的方式构造整个应用,并且可以将单层框架以最佳的组合揉和在一起建立一个连贯的体系。可以说Spring是一个提供了更完善开发环境的一个框架,可以为POJO(Plain Ordinary Java Object)对象提供企业级的服务。
Spring的形成,最初来自Rod Jahnson所著的一本很有影响力的书籍《Expert One-on-One J2EE Design and Development》,就是在这本书中第一次出现了Spring的一些核心思想,该书出版于2002年。另外一本书《Expert One-on-One J2EE Development without EJB》,更进一步阐述了在不使用EJB开发JAVA EE企业级应用的一些设计思想和具体的做法。有时间了可以详细的研读一下。
Spring的初衷:
1、JAVA EE开发应该更加简单。
2、使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。
3、为JavaBean提供了一个更好的应用配置框架。
4、更多地强调面向对象的设计,而不是现行的技术如JAVA EE。
5、尽量减少不必要的异常捕捉。
6、使应用程序更加容易测试。
Spring的目标:
1、可以令人方便愉快的使用Spring。
2、应用程序代码并不依赖于Spring APIs。
3、Spring不和现有的解决方案竞争,而是致力于将它们融合在一起。
Spring的基本组成:
1、最完善的轻量级核心框架。
2、通用的事务管理抽象层。
3、JDBC抽象层。
4、集成了Toplink, Hibernate, JDO, and iBATIS SQL Maps。
5、AOP功能。
6、灵活的MVC Web应用框架。
Spring架构
推荐书籍:Spring in Action
J2EE三层结构的演变
package com.sxt.factory;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class ObjectFactory {
/**
* ioc 容器
* key 类的全路径
* value 类的对象
*/
public static Map<String,Object> ioc = new HashMap<String,Object>();
/**
* @Title: getInstance
* @author: Mr.T
* @date: 2019年11月20日 上午10:54:28
* @Description:
* 这种方案不足 ,利用反射的灵活可以创建各种对象,减少工厂的个数.但是 效率堪忧.
* 发现效率低的原因,由于IOC容器没有对象,所以需要使用反射进行创建对象,再放入IOC容器.
* 如果,需要使用时,IOC容器存在需要使用的对象,那么效率不仅仅没有降低,且提高了.
* 当项目启动时,就直接将需要创建的对象,放入IOC容器中
* @param <T>
* @param cls
* @return
* @return: T
*/
public static <T> T getInstance(Class<T> cls) {
/**
* 每次创建对象都是创建新的对象
*/
T t = null;
// 获取类的全路径
String key = cls.getName();
// 判断对象容器中是否存在 若存在直接取
if(ioc.containsKey(key)) {
return (T) ioc.get(key);
}
// 若不存在 则创建一个,返回 ,且将对象放入到IOC容器中
try {
t = cls.newInstance();
ioc.put(key, t);
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
public void init() {
InputStream in = ObjectFactory.class.getClassLoader().getResourceAsStream("obj.properties");
Properties prop = new Properties();
try {
prop.load(in);
String dao = prop.getProperty("dao");
String service = prop.getProperty("service");
String[] classes = dao.split(",");
for (int i = 0; i < classes.length; i++) {
Class<?> cls = Class.forName(classes[i]);
String name = cls.getName();
Object obj = cls.newInstance();
ioc.put(name, obj);
}
classes = service.split(",");
for (int i = 0; i < classes.length; i++) {
Class<?> cls = Class.forName(classes[i]);
String name = cls.getName();
Object obj = cls.newInstance();
ioc.put(name, obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
dao=com.sxt.dao.impl.UserDaoImpl,com.sxt.dao.impl.ClassesDaoImpl
service=com.sxt.service.impl.UserServiceImpl,com.sxt.service.impl.ClassesServiceImpl
Spring应用
在实际开发中,对象和方法是最基础,最核心的东西.Spring核心只进行对象和方法的管理.对象的管理,在Spring中被称之为IOC/DI-控制反转(Inversion of Control,缩写为IoC).
IOC控制反转:
将对象的创建初始化的权利,从开发者手中转移到Spring容器.由Spring将程序中需要的对象进行创建和装配.减少了开发者对对象的管理工作.这种模式就被称之为控制反转.
DI—Dependency Injection,即“依赖注入”:
-
IoC的别名,2004年,Martin Fowler探讨了同一个问题,既然IoC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理对象变为由IoC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection,DI)”。他的这个答案,实际上给出了实现IoC的方法:注入。
-
所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
-
所以,依赖注入(DI)和控制反转(IoC)是从不同的角度描述的同一件事情,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦
Spring入门使用
spring下载地址:https://repo.spring.io/webapp/#/artifacts/browse/tree/General/release
- 下载jar包
Spring Framework 5.2.x: JDK 8-14
Spring Framework 5.1.x: JDK 8-12
Spring Framework 5.0.x: JDK 8-10
Spring Framework 4.3.x: JDK 6-8
Spring各个jar包作用
spring-aop:Spring的面向切面编程,提供AOP(面向切面编程)的实现
spring-aspects:Spring提供的对AspectJ框架的整合
spring-beans:Spring IOC的基础实现,包含访问配置文件、创建和管理bean等。
spring-context:在基础IOC功能上提供扩展服务,此外还提供许多企业级服务的支持,有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持。
spring-context-support:Spring context的扩展支持,用于MVC方面。
spring-core:Spring的核心工具包
spring-expression:Spring表达式语言
spring-instrument:Spring对服务器的代理接口
spring-instrument-tomcat:Spring对tomcat连接池的集成
spring-jdbc:对JDBC 的简单封装
spring-jms:为简化jms api的使用而做的简单封装
spring-messaging:消息支持相关包
spring-orm:整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现
spring-oxm:Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换
spring-test:对JUNIT等测试框架的简单封装
spring-tx:为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。
spring-web:包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。
spring-webmvc:包含SpringMVC框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、 Tiles、Velocity、XSLT相关类。当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类。
spring-webmvc-portlet:Spring MVC的增强
spring-websocket:提供 Socket通信, web端的推送功能
Spring的IOC配置
导入IOC相关jar包
spring-beans-4.3.24.RELEASE.jar
spring-context-4.3.24.RELEASE.jar
spring-context-support-4.3.24.RELEASE.jar
spring-core-4.3.24.RELEASE.jar
spring-expression-4.3.24.RELEASE.jar
日志包
commons-logging-1.2.jar
log4j-1.2.17.jar
log4j-api-2.11.2.jar
log4j-core-2.11.2.jar
Spring配置文件:
<?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="user" class="com.sxt.bean.User" />
</beans>
测试程序
package com.sxt.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.bean.User;
public class Test {
public static void main(String[] args) {
// 引入配置文件 读取配置信息
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
//new User()
// 此时使用 spring 容器 : 根据指定的类,就可以获取这个类的对象
// 说明容器中,本身就存在这个对象,那么一定有人创建了对象,创建人不是程序员,是Spring
// 此时 创建对象的权利,从开发者的手中,移交到Spring框架.这就是IOC (控制反转)
// 创建对象,控制对象的生命周期的角色发生反转,所以被称之为控制反转
// 从Spring IOC容器中获取对象
User bean = context.getBean(User.class);
// 使用对象调用方法
bean.study();
System.out.println(bean);
User bean2 = context.getBean(User.class);
System.out.println(bean2);
}
}
Spring创建对象的三种方式
方式一:构造方法
使用构造器创建Bean对象,必须要有无参构造方法
<!--
id : bean标签唯一标识 也是对象唯一标识 一个bean只有一个ID值且整个IOC容器ID值不允许重复
name : bean标签中name属性,也是对象的name值,name值可以多个,使用逗号分隔.当name值没有时,id值就是name值
class : 需要创建对象的类
-->
<bean id="user" name="user1,user2,user3" class="com.sxt.bean.User" />
方式二:静态工厂
<!--
方式二: 使用静态工厂方式
class : 工厂类
factory-method : 工厂方法
-->
<bean id="userFactory" class="com.sxt.factory.UserFactory" factory-method="getUser"></bean>
package com.sxt.factory;
import com.sxt.bean.User;
public class UserFactory {
public static User getUser() {
return new User();
}
}
方式三:非静态工厂
<!--
方式三: 非静态工厂
factory-bean : 工厂对象
factory-method : 工厂方法
-->
<!-- 创建工厂对象,用于调用工厂中非静态的方法 -->
<bean id="userDyFactory" class="com.sxt.factory.UserDyFactory"></bean>
<!-- 根据工厂对象,工厂方法创建Bean对象 -->
<bean id="userBean" factory-bean="userDyFactory" factory-method="getUser"></bean>
package com.sxt.factory;
import com.sxt.bean.User;
public class UserDyFactory {
/**
* 非静态方法
*/
public User getUser() {
return new User();
}
}
Spring IOC【控制反转】
什么是IOC:
IOC(Inversion of Control)控制反转。控制反转不是一种新的技术而是一种设计思想,控制反转指的是创建对象的控制权反转了,以前是创建对象的主动权和创建时机是由自己把控的,该对象的依赖对象也需要手动去创建、注入,现在这个控制权交给了Spring容器,由Spring容器去管理,去创建对象,同时对象之间的依赖关系也没有了,他们都依赖于Spring容器,通过Spring容器去建立他们之间的关系。降低程序之间的耦合度
SpringIOC的基本使用
作用:
IOC将耦合性非常高的对象进行解耦。
使用:
什么时候使用IOC对对象进行解耦是一个主观问题,应当根据代码的结构以及功能的需求进行分析,然后决定哪些对象之间需要使用IOC解耦。一般情况下,在MVC代码结构中,会将Servlet和Service之间解耦,Service和mapper之间解耦。
基本使用流程:
1、导入IOC的jar包
2、在src下声明并配置applicationcontext.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="us" class="com.sxt.service.impl.ServiceImpl"></bean>
</beans>
3、在代码中创建ApplicationContext对象,并获取Spring容器中的对象,然后完成功能 开发
package com.sxt.controller;
import com.sxt.service.ServiceA;
import com.sxt.service.impl.ServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/myServletIOC")
public class MyServletIOC extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置编码格式
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//获取请求信息
String name = req.getParameter("name");
int age = Integer.parseInt(req.getParameter("age"));
//处理请求信息
//创建Spring容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//从Spring容器对象获取业务层对象
ServiceA serviceA = (ServiceA) ac.getBean("us");
//调用业务层方法完成功能处理
serviceA.testA(name,age);
//响应
resp.getWriter().println("学习愉快。");
}
}
SpringIOC创建对象的三种方式
问题及解决
使用IOC解耦层与层之间的逻辑关系,但是我们发现,对象由以前我们自己根据需求在代码中直接new创建,变为从Spring容器中获取,也就说对象的创建由Spring容器来创建,我们直接获取使用即可。那么,如果我们需要一个带有指定的初始化数据的对象,如何让Spring容器对象帮我们创建呢?
解决:
在applicationcontext.xml配置文件中,配置对象的创建方式以及初始化的方式。
1、通过构造器方式
①无参数构造器(创建一个没有初始化数据的对象)
②有参 数构造器(创建一个带有初始化数据的对象)
Applicationcontext.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">
<!--创建student的bean对象-->
<!--构造器方式-->
<!--
无参构造器
特点:Spring容器默认使用无参构造方式创建对象
使用:在配置文件中直接使用bean标签配置即可,无需过多声明
-->
<bean id="stu" class="com.sxt.pojo.Student"></bean>
<!--有参数的构造器
特点:Spring容器对根据配置调用的有参构造器创建一个带有初始化数据的对象
使用:constructor-arg:使用bean的字标签来声明调用的构造器的形参的个数
一个字标签表示一个参数
属性:index:参数的下标
type:参数的类型,全限定路径
name:参数的形参名
value:参数要给的值
-->
<bean id="stu2" class="com.sxt.pojo.Student">
<constructor-arg index="0" type="java.lang.Integer" name="sid" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" name="sname" value="张三"></constructor-arg>
</bean>
</beans>
TestObject代码示例:
package com.sxt.controller;
import com.sxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testStu {
public static void main(String[] args) {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
//获取容器中的对象
//无参构造器方式
Student student = (Student) ac.getBean("stu");
System.out.println("无参构造:"+student);
//有参构造器
Student student1= (Student) ac.getBean("stu2");
System.out.println("有参构造:"+student1);
}
}
2、通过属性注入(get/set)
先通过空构造器创建一个对象,然后再使用set方法进行初始化赋值。
Applicationcontext.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">
<!--创建student的bean对象-->
<!--
属性注入方式
特点:相当于创建一个空对象然后使用set方法赋值
使用:
property:在bean标签下使用子标签property,表示调用set方法给某个属性赋值
属性:name:要赋值的属性名
value:值
-->
<bean id="stu3" class="com.sxt.pojo.Student">
<property name="sid" value="2"></property>
<property name="sname" value="李四"></property>
</bean>
</beans>
TestObject代码示例:
package com.sxt.controller;
import com.sxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testStu {
public static void main(String[] args) {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
//获取容器中的对象
//属性注入方式
Student student = (Student) ac.getBean("stu3");
System.out.println("属性注入方式"+student);
}
}
3、通过工厂模式
本质就是封装对象的创建过程的一种代码的编程思想。
①动态工厂模式
②静态工厂模式
Applicationcontext.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">
<!--创建student的bean对象-->
<!--工厂设计模式-->
<!--动态工厂-->
<bean id="factory" class="com.sxt.pojo.StudentFactory"></bean>
<!--生产Student对象-->
<bean id="stu4" factory-bean="factory" factory-method="newIntance"></bean>
<!--静态工厂-->
<!--可以理解为静态方法直接用类名调用-->
<bean id="stu5" class="com.sxt.pojo.StudentFactory2" factory-method="newIntance"></bean>
</beans>
TestObject代码示例:
package com.sxt.controller;
import com.sxt.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testStu {
public static void main(String[] args) {
//创建容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationcontext.xml");
//获取容器中的对象
//动态工厂
Student student = (Student) ac.getBean("stu4");
System.out.println("动态工厂:"+student);
//静态工厂
Student student1 = (Student) ac.getBean("stu5");
System.out.println("静态工厂:"+student1);
}
}
IOC相关注解
为了简化开发,Spring提供了一些内置注解:
@Component:表示是一个组件,使用该注解修饰类,Spring自动为其创建对象,放入IOC容器
@Service:继承于Component 注解,表示一个组件,主要用于Service层
@Repository:继承于Component 注解,表示一个组件,主要用持久层
@Controller:继承于Component 注解,表示一个组件,主要用于控制层
@Autowired:用于为属性进行自动装配
@Qualifier(name):组件名称
导入jar包
spring-aop-4.3.24.RELEASE.jar
引入xml约束
aop约束
context约束
配置组件扫描
<?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:aop="http://www.springframework.org/schema/aop"
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 https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描注解组件,使其生效 -->
<context:component-scan base-package="com.sxt.dao.impl,com.sxt.service.impl,com.sxt.controller"></context:component-scan>
<!-- 包下面所有的类都要进行扫描 -->
<!-- <context:component-scan base-package="com.sxt"></context:component-scan> -->
</beans>
DI 【依赖注入】
依赖注入(Dependency Injection) DI
组件之间的依赖关系由容器在运行期间决定,即由容器动态的将某个依赖关系注入到组件中;
依赖注入的目的不在于为软件系统提供更多的功能,它的主要目的在于提升组件重用的频度,并为软件搭建一个灵活,可扩展的平台,通过依赖注入,我们只需要简单的配置,不需要任何代码就可以指定目标的资源,完成自身的业务逻辑,不需要关心具体的资源来自何处有谁实现。
Spring的属性注入
构造方法注入
<?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="user1" class="com.sxt.bean.User"></bean>
<!-- 创建对象: 2个参数的构造方法 -->
<bean id="user2" class="com.sxt.bean.User">
<constructor-arg index="0" value="韩梅梅"></constructor-arg>
<constructor-arg index="1" value="女"></constructor-arg>
</bean>
<!-- 创建对象: 3个参数的构造方法 -->
<bean id="user3" class="com.sxt.bean.User">
<constructor-arg index="0" value="韩梅梅"></constructor-arg>
<constructor-arg index="1" value="女"></constructor-arg>
<constructor-arg index="2" value="18"></constructor-arg>
</bean>
<!-- 创建对象: 构造方法 参数名称注入属性值 -->
<bean id="user4" class="com.sxt.bean.User">
<constructor-arg name="name" value="韩梅梅"></constructor-arg>
<constructor-arg name="sex" value="女"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
</beans>
package com.sxt.bean;
public class User {
// private String name;
// private String sex;
// private Integer age;
private String name1;
private String sex1;
private Integer age1;
public User() {
System.out.println("我是无参构造方法");
}
public User(String name, String sex) {
this.name1 = name;
this.sex1 = sex;
}
public User(String name, String sex, Integer age) {
this.name1 = name;
this.sex1 = sex;
this.age1 = age;
}
public void study() {
System.out.println("我是学习方法");
}
public String getName() {
return name1;
}
public void setName(String name) {
this.name1 = name;
}
public String getSex() {
return sex1;
}
public void setSex(String sex) {
this.sex1 = sex;
}
public Integer getAge() {
return age1;
}
public void setAge(Integer age) {
this.age1 = age;
}
@Override
public String toString() {
return "User [name=" + name1 + ", sex=" + sex1 + ", age=" + age1 + "]";
}
}
使用set方法注入属性值
<!--
方式二: 使用set方法注入属性
此时的name 值 不是真的类中属性名 只 set方法中setXxx中xxx
-->
<bean id="user5" class="com.sxt.bean.User">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
<property name="age" value="18"></property>
</bean>
package com.sxt.bean;
public class User {
private String name1;
private String sex1;
private Integer age1;
public User() {
System.out.println("我是无参构造方法");
}
public User(String name, String sex) {
this.name1 = name;
this.sex1 = sex;
}
public User(String name, String sex, Integer age) {
this.name1 = name;
this.sex1 = sex;
this.age1 = age;
}
public void study() {
System.out.println("我是学习方法");
}
public String getName() {
return name1;
}
public void setName(String name) {
this.name1 = name;
}
public String getSex() {
return sex1;
}
public void setSex(String sex) {
this.sex1 = sex;
}
public Integer getAge() {
return age1;
}
public void setAge(Integer age) {
this.age1 = age;
}
@Override
public String toString() {
return "User [name=" + name1 + ", sex=" + sex1 + ", age=" + age1 + "]";
}
}
各种类型的属性注入
<?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">
<!--
各种类型的属性的注入
-->
<!-- 1. 注入字符串 -->
<bean id="user1" class="com.sxt.bean.User">
<property name="str" value="我是字符串"></property>
</bean>
<!-- 2. 注入对象 方式一 -->
<bean id="st1" class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"> </property>
<property name="sex" value="女"> </property>
</bean>
<!--
在注入属性值时,value 只能注入:基本数据类型和字符串,如果是对象,需要使用 ref 进行对相关联
-->
<bean id="user2" class="com.sxt.bean.User">
<property name="st" ref="st1" >
</property>
</bean>
<!-- 注入对象方式二 -->
<bean id="user3" class="com.sxt.bean.User">
<property name="st">
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"> </property>
<property name="sex" value="女"> </property>
</bean>
</property>
</bean>
<!--3 .注入数组结构 -->
<bean id="user4" class="com.sxt.bean.User">
<property name="list1">
<array>
<value>韩梅梅</value>
<value>李磊</value>
<value>Jim</value>
<value>Lucy</value>
</array>
</property>
</bean>
<!-- list结构属性 -->
<bean id="user5" class="com.sxt.bean.User">
<property name="list1">
<list>
<value>韩梅梅</value>
<value>李磊</value>
<value>Jim</value>
<value>Lucy</value>
</list>
</property>
</bean>
<bean id="user6" class="com.sxt.bean.User">
<property name="list2">
<list>
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
</bean>
<bean class="com.sxt.bean.Student">
<property name="name" value="Lucy"></property>
<property name="sex" value="女"></property>
</bean>
<ref bean="st1"/>
</list>
</property>
</bean>
<!-- set结构属性 -->
<bean id="user7" class="com.sxt.bean.User">
<property name="set1">
<set>
<value>字符串1</value>
<value>字符串2</value>
<value>字符串3</value>
<value>字符串1</value>
<value>字符串1</value>
</set>
</property>
</bean>
<bean id="user8" class="com.sxt.bean.User">
<property name="set2">
<set>
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
</bean>
<bean class="com.sxt.bean.Student">
<property name="name" value="Lucy"></property>
<property name="sex" value="女"></property>
</bean>
<ref bean="st1"/>
</set>
</property>
</bean>
<!-- map结构 -->
<bean id="user9" class="com.sxt.bean.User">
<property name="map1">
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
<entry key="key3" value="value3"></entry>
<entry key="key4" value="value4"></entry>
</map>
</property>
</bean>
<bean id="user10" class="com.sxt.bean.User">
<property name="map2">
<map>
<entry key="key1" value-ref="st1"></entry>
<entry key="key2" >
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
</bean>
</entry>
</map>
</property>
</bean>
<!-- properties 对象 -->
<bean id="user11" class="com.sxt.bean.User">
<property name="prop">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
<prop key="key3">value3</prop>
</props>
</property>
</bean>
</beans>
package com.sxt.bean;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class User {
private String str; // 字符串
private Student st; // 对象
private List<String> list1; //list集合
private List<Student> list2; //list集合
private Set<String> set1; //set集合
private Set<Student> set2; //set集合
private Map<String,String> map1; // Map
private Map<String,Student> map2; // Map
private Properties prop; // properties
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public Student getSt() {
return st;
}
public void setSt(Student st) {
this.st = st;
}
public List<String> getList1() {
return list1;
}
public void setList1(List<String> list1) {
this.list1 = list1;
}
public List<Student> getList2() {
return list2;
}
public void setList2(List<Student> list2) {
this.list2 = list2;
}
public Set<String> getSet1() {
return set1;
}
public void setSet1(Set<String> set1) {
this.set1 = set1;
}
public Set<Student> getSet2() {
return set2;
}
public void setSet2(Set<Student> set2) {
this.set2 = set2;
}
public Map<String, String> getMap1() {
return map1;
}
public void setMap1(Map<String, String> map1) {
this.map1 = map1;
}
public Map<String, Student> getMap2() {
return map2;
}
public void setMap2(Map<String, Student> map2) {
this.map2 = map2;
}
public Properties getProp() {
return prop;
}
public void setProp(Properties prop) {
this.prop = prop;
}
}
spring属性介绍
<?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">
<!--
注意:
在spring中,默认会根据配置文件创建对象放入到ioc容器中
lazy-init : 是否懒加载 default/false : 不进行懒加载 ,程序启动加载对象.true 进行懒加载,只有使用时才加载
scope : 对象作用域
singleton : 单例 默认
prototype : 非单例
request : 每次请求创建对象
session : 每次会话
init-method :
初始化方法 对象创建后进行对象初始化调用的方法
destroy-method :
ioc容器中,对象销毁时调用的方法
autowire :自动装配对象属性
byType : 根据类型装配
byName : 根据属性的name装配
autowire-candidate : 是否被自动装配查找
true : 可以被自动装配 默认
false : 不可以被自动装配
primary :
在装配时,推荐使用的
abstract : 是否是抽象类
parent : 父级,可以进行属性继承
depends-on : 依赖的Bean
-->
<bean id="user1" class="com.sxt.bean.User" scope="singleton" init-method="init" destroy-method="destory" depends-on="st" ></bean>
<bean id="st" class="com.sxt.bean.Student" autowire-candidate="default" >
<property name="name" value="韩梅梅"></property>
<property name="sex" value="18"></property>
</bean>
</beans>
spring改造web3层结构
pojo
package com.sxt.pojo;
public class User {
private String name;
private Integer age;
public User() {}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
dao
package com.sxt.dao;
import java.util.List;
import com.sxt.pojo.User;
public interface IUserDao {
public List<User> selectAll();
}
dao.impl
package com.sxt.dao.impl;
import java.util.ArrayList;
import java.util.List;
import com.sxt.dao.IUserDao;
import com.sxt.pojo.User;
public class UserDaoImpl implements IUserDao{
@Override
public List<User> selectAll() {
System.out.println("dao 层 selectAll");
List<User> list = new ArrayList<User>();
list.add(new User("韩梅梅", 18));
list.add(new User("Lucy", 18));
list.add(new User("Lily", 18));
return list;
}
}
service
package com.sxt.service;
import java.util.List;
import com.sxt.pojo.User;
public interface IUserService {
public List<User> queryAll();
}
service.impl
package com.sxt.service.impl;
import java.util.List;
import com.sxt.dao.IUserDao;
import com.sxt.pojo.User;
import com.sxt.service.IUserService;
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
@Override
public List<User> queryAll() {
return userDao.selectAll();
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
}
controller
package com.sxt.controller;
import java.util.List;
import com.sxt.pojo.User;
import com.sxt.service.IUserService;
public class UserController {
private IUserService userService;
public void list() {
List<User> users = userService.queryAll();
for (User user : users) {
System.out.println(user);
}
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
}
配置文件:
<?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">
<!-- 配置Dao 层 -->
<bean id="userDao" class="com.sxt.dao.impl.UserDaoImpl"></bean>
<!-- 配置Service -->
<bean id="userService" class="com.sxt.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 配置controller -->
<bean id="userController" class="com.sxt.controller.UserController">
<property name="userService" ref="userService"></property>
</bean>
</beans>
测试类:
package com.sxt.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.controller.UserController;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
UserController bean = context.getBean(UserController.class);
bean.list();
}
}
IOC相关注解
为了简化开发,Spring提供了一些内置注解:
@Component:表示是一个组件,使用该注解修饰类,Spring自动为其创建对象,放入IOC容器
@Service:继承于Component 注解,表示一个组件,主要用于Service层
@Repository:继承于Component 注解,表示一个组件,主要用持久层
@Controller:继承于Component 注解,表示一个组件,主要用于控制层
@Autowired:用于为属性进行自动装配
@Qualifier(name):组件名称
导入jar包
spring-aop-4.3.24.RELEASE.jar
引入xml约束
aop约束
context约束
配置组件扫描
<?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:aop="http://www.springframework.org/schema/aop"
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 https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描注解组件,使其生效 -->
<context:component-scan base-package="com.sxt.dao.impl,com.sxt.service.impl,com.sxt.controller"></context:component-scan>
<!-- 包下面所有的类都要进行扫描 -->
<!-- <context:component-scan base-package="com.sxt"></context:component-scan> -->
</beans>
Spring AOP 【面向切面】
AOP的概念
AOP(Aspect Oriented Programming)面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
Spring的IoC是管理对象,使用AOP管理方法。如何管理方法,扩展方法,如何扩展方法?方法中套方法,装饰者模式。
但是装饰者模式,需要类与类之间存在关系.提高了程序耦合读,不便于维护和扩展.基于这个原因,开发者提出了AOP的想法,面向切面编程 ----- 横向扩展程序.这种扩展方式,也被称之为拔插式的扩展,需要使用时,只需要织入想要扩展的内容,不需要时,只需要取消织入. 具体的实现,依赖动态代理模式,相对于纵向扩展,编码的复杂度高一些,但是代码灵活一些。
场景
- 事务管理
开启事务
关闭事务
回滚事务
- 日志采集
将请求信息进行持久化.发生请求信息获得方式都一样,只需要将请求对象统一保存.数据分析.
JDK代理
代理,代替打理。
静态代理
package com.sxt.target;
/**
* 被代替的类
*/
public class TargetClass {
public void sing() {
System.out.println(" 世上只有妈妈好 ");
}
}
package com.sxt.target;
/**
* 代理类
*/
public class ProxyClass {
// 被代理的对象
TargetClass targetClass;
public ProxyClass(TargetClass targetClass) {
super();
this.targetClass = targetClass;
}
public void sing() {
System.out.println("查看行程计划");
System.out.println("确定时间");
System.out.println("修改行程计划");
System.out.println("下周二");
targetClass.sing();
}
}
package com.sxt.target;
public class Test {
public static void main(String[] args) {
// 被代理的对象
TargetClass targetClass = new TargetClass();
// 创建代理类
ProxyClass proxyClass = new ProxyClass(targetClass);
//调用方法
proxyClass.sing();
}
}
静态代理的不足:
必须定义代理类,且代理的方法声明了,扩展性相对较差.类和类之间产生了关系,耦合性加强了.不便于维护 ,代码的可读性也会降低。
动态代理
动态的为需要代理的类,创建一个具体的代理类.不再需要开发者定义具体的代理的类.这种方式,就是动态代理.JDK为此制定了一个标准.
类: Proxy代理类,所有代理的类基类
Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类.
newProxyInstance(ClassLoader loader, Class<?>... interfaces,InvocationHandler hanlder) : 类加载器 当前类的加载器,interfaces 接口的Class对象 hanlder 代理类的处理器
接口:InvocationHandler 与代理类关联调用程序的处理器
配置类:
package com.sxt.target;
/**
* 配置类
*/
public class Config {
//开启事务的方法的名称的前缀
public static String[] preFix = {"add","update","delete"};
}
代理类处理器
package com.sxt.target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理类绑定的代理处理器
*/
public class ProxyHanlder implements InvocationHandler {
// 被代理的目标 此时类型时 Object 那么传入任何类型都可以
private Object proxyTarget;
public ProxyHanlder(Object proxyTarget) {
this.proxyTarget = proxyTarget;
}
/**
* proxy : ProxyHanlder 对象 代理处理器对象
* method : 被代理调用的方法
* args : 方法中参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
for (String name : Config.preFix) {
if(methodName.startsWith(name)) {
new TransctionManager().beginTrancation();
}
}
Object obj = method.invoke(proxyTarget, args);
for (String name : Config.preFix) {
if(methodName.startsWith(name)) {
new TransctionManager().commitTrancation();
}
}
return obj;
}
}
被代理目标类:
package com.sxt.target;
/**
* @ClassName: TargetClassInteterface
* @Description: 被代理的类的接口
* @author: Mr.T
* @date: 2019年11月22日 上午11:14:03
*/
public interface TargetClassInteterface {
public void addUser(String name) ;
public void deleteUser() ;
public void updateUser() ;
public void selectUser() ;
}
package com.sxt.target;
/**
* @ClassName: TargetClass
* @Description: 具体的代理类
* @author: Mr.T
* @date: 2019年11月22日 上午11:15:19
*/
public class TargetClass implements TargetClassInteterface {
@Override
public void addUser(String name) {
System.out.println("新增用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
@Override
public void updateUser() {
System.out.println("修改用户");
}
@Override
public void selectUser() {
System.out.println("查询用户");
}
}
增强的内容:
package com.sxt.target;
/**
* @ClassName: TransctionManager
* @Description: 事务管理器 增强的具体内容
* @author: Mr.T
* @date: 2019年11月22日 上午11:35:37
*/
public class TransctionManager {
public void beginTrancation() {
System.out.println("开启事务");
}
public void commitTrancation() {
System.out.println("提交事务");
}
}
测试类:
package com.sxt.target;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
// 生成代理编译后的文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 创建了被代理的目标
TargetClassInteterface targetInterface = new TargetClass();
// 创建代理类的处理器
ProxyHanlder proxyHandler = new ProxyHanlder(targetInterface);
// 创建代理类
TargetClassInteterface proxyObj = (TargetClassInteterface) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {TargetClassInteterface.class}, proxyHandler);
proxyObj.addUser("user");
System.out.println("======================");
proxyObj.deleteUser();
System.out.println("======================");
proxyObj.updateUser();
System.out.println("======================");
proxyObj.selectUser();
System.out.println("======================");
}
}
不足:
- 必须依赖接口,具有一定局限性。
- 由于使用的反射,所以效率相对较低。
源码分析
package com.sun.proxy;
import com.sxt.target2.TargetClassInteterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
// 生成的代理类 $Proxy0 是 Proxy 子类且是 TargetClassInteterface 实现类
// 那么这个代理类就要有 TargetClassInteterface 里面抽象方法
public final class $Proxy0 extends Proxy implements TargetClassInteterface {
private static Method m0; // ======> Object类中的 hashCode
private static Method m1; // ======> Object类中的 equals
private static Method m2; // ======> Object类中的 toString
private static Method m3; // ======> 实现了接口中 addUser 方法
static
{
try {
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.sxt.target2.TargetClassInteterface").getMethod("addUser", new Class[] { Class.forName("java.lang.String") });
return;
}
catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
// 创建代理类对象 InvocationHandler 对象 本质上就是传入 ProxyHanlder 自己定义的代理类程序处理器
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
// 调用父类的有参构造方法 : 将自己定义 ProxyHanlder 传给Proxy
super(paramInvocationHandler);
// 将自己定义的处理器 赋值给了 Proxy 类中 h 成员变量
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
// 在测试类中,使用创建出来的代理对象 调用 addUser ,其实就是调用此处的addUser
public final void addUser(String paramString)
throws
{
try
{
// this.h : ProxyHandler对象
// this.h 当前类中h变量 当前类中没有 h 所以h是从父类 Proxy类继承而来.
// this.h 就是父类Proxy中h,而Proxy中h ,是自定义的ProxyHandler
// proxyHandler.invoke(this,m3,paramString); //this : proxy 代理类对象 m3 具体的add方法 paramString 传入的参数
// 调用Proxy Handler的 invoke 方法
/*
// 被代理的目标 此时类型时 Object 那么传入任何类型都可以
private Object proxyTarget;
public ProxyHanlder(Object proxyTarget) {
this.proxyTarget = proxyTarget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beginTrancation(); // 开启事务
//m3 addUser.invoke(obj ,args ) : // 此时的obj :proxyTarget ----> 被代理的具体目标类对象 addUser(String name) { 新增用户 }
Object obj = method.invoke(proxyTarget, args);
commitTrancation();
return obj;
}
*/
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
}
JDK动态代理的不足:
结构相对复杂,必须依赖接口.被代理的对象要有接口(接口要当做参数传递).其二,其本质是使用的反射,执行效率相对而言较低.
由于以上原因,Cglib出现,解决以上问题.
Cglib动态代理
问题1:必须要有接口,没有接口如何实现动态代理?
既然没有接口,那么使用子类,使用继承。
问题2:利用反射执行效率低,如何解决效率低?
执行效率低,创建对象,低在方法查找。那么将需要代理的方法创建好,存储在容器中,需要使用时,根据方法对应的索引,找到方法.。
Cglib使用
-
导入jar包
asm-7.0.jar cglib-3.2.10.jar
-
编写代码
目标类
package com.target;
/**
* 被代理的类
*/
public class TargetClass {
public void sing() {
System.out.println("唱歌");
}
}
增强类
package com.target;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 方法拦截器
*/
public class MyMethodIntercepter implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
// obj : 子类对象 ----父类 TargetClass
// args : 参数
// cglib的动态代理 不是反射. 使用 索引找到该方法
Object rs = proxy.invokeSuper(obj, args);
after();
return rs;
}
public void before() {
System.out.println("前置增强");
}
public void after() {
System.out.println("后置增强");
}
}
创建代理类:
package com.target;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://java");
// 创建增强器
Enhancer enhancer = new Enhancer();
// 增强的目标
enhancer.setSuperclass(TargetClass.class);
// 使用谁增强
enhancer.setCallback(new MyMethodIntercepter());
// 创建代理类
TargetClass obj = (TargetClass) enhancer.create();
// 调用方法
obj.sing();
}
}
package com.target;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.reflect.FastClass;
public class Test2 {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://java");
FastClass create = FastClass.create(TargetClass.class);
//获取方法的索引
int index = create.getIndex("sing", new Class[] {});
//调用方法
try {
create.invoke(index, new TargetClass(), null);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Cglib动态代理的不足
- 由于Cglib使用继承,所以无法代理final修饰类
- 也无法代理final修饰的方法
spring-Aop 配置方式一
-
导入jar包
aspectjweaver.jar commons-logging-1.2.jar log4j-1.2.17.jar log4j-api-2.11.2.jar log4j-core-2.11.2.jar spring-aspects-4.3.24.RELEASE.jar spring-beans-4.3.24.RELEASE.jar spring-context-4.3.24.RELEASE.jar spring-context-support-4.3.24.RELEASE.jar spring-core-4.3.24.RELEASE.jar spring-expression-4.3.24.RELEASE.jar
-
编写代码
被增强的目标
package com.sxt.target;
/**
* 目标类接口
*/
public interface ITargetClass {
/**
* 唱歌方法
*/
public void sing();
}
package com.sxt.target.impl;
import com.sxt.target.ITargetClass;
public class TargetClassImpl implements ITargetClass{
@Override
public void sing() {
int m = 0;
System.out.println(1/m);
System.out.println(" 月亮代表我的心 ");
}
}
增强类:
package com.sxt.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置增强");
}
}
package com.sxt.advice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
/**
* 后置增强类
*/
public class AfterAdvice implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置增强");
}
}
package com.sxt.advice;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* 环绕增强
*/
public class RoundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//调用前置增强
beforeAdvice();
//目标方法执行
Method method = invocation.getMethod(); //目标方法
Object[] arguments = invocation.getArguments(); //目标方法的参数
//执行当前目标方法
Object rs = invocation.proceed();
afterAdvice();
return rs;
}
public void beforeAdvice() {
System.out.println("前置增强");
}
public void afterAdvice() {
System.out.println("后置增强");
}
}
package com.sxt.advice;
import org.springframework.aop.ThrowsAdvice;
public class ExceptionAdvice implements ThrowsAdvice{
/**
* 方法名必须为afterThrowing 且要有 Throwable 参数
*/
public void afterThrowing(Throwable th) {
System.out.println("我是异常增强,发生异常时我执行");
}
}
aop配置
<?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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置增强的目标 -->
<bean id="targetClass" class="com.sxt.target.impl.TargetClassImpl"></bean>
<!-- 具体增强类对象 -->
<!-- 前置增强 -->
<bean id="beforeAdvice" class="com.sxt.advice.BeforeAdvice"></bean>
<!-- 后置增强 -->
<bean id="afterAdvice" class="com.sxt.advice.AfterAdvice"></bean>
<!-- 环绕增强 -->
<bean id="roundAdvice" class="com.sxt.advice.RoundAdvice"></bean>
<!-- 异常增强 -->
<bean id="exceptionAdvice" class="com.sxt.advice.ExceptionAdvice"></bean>
<!-- 织入: 将切点 和 具体增强类结合 -->
<!-- 进行AOP配置 -->
<aop:config>
<!-- 配置切入点 : 需要增强的方法 -->
<aop:pointcut expression="execution(* com.sxt.target.impl.TargetClassImpl.*(..))" id="pointcut" />
<!-- 配置切面方法 -->
<!-- <aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointcut"/> -->
<!-- <aop:advisor advice-ref="afterAdvice" pointcut-ref="pointcut"/> -->
<!-- <aop:advisor advice-ref="roundAdvice" pointcut-ref="pointcut"/> -->
<aop:advisor advice-ref="exceptionAdvice" pointcut-ref="pointcut" />
</aop:config>
</beans>
测试:
package com.sxt.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.target.ITargetClass;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
ITargetClass obj = (ITargetClass) context.getBean("targetClass");
obj.sing();
}
}
Spring-Aop 配置方式二
AspectJ是一个基于Java语言的AOP框架,Spring2.0开始引入对AspectJ的支持,AspectJ扩展了Java语言,提供了专门的编译器,在编译时提供了横向代码的注入。
@AspectJ是AspectJ1.5新增功能,通过JDK1.5注解技术,允许直接在Bean中定义切面
新版本的Spring中,建议使用AspectJ方式开发AOP
编写目标类:
package com.sxt.target;
/**
* 目标类接口
*/
public interface ITargetClass {
/**
* 唱歌方法
*/
public void sing();
}
package com.sxt.target.impl;
import com.sxt.exception.MyException;
import com.sxt.target.ITargetClass;
public class TargetClassImpl implements ITargetClass{
@Override
public void sing() {
throw new MyException("4001001", "自己定义的异常");
// System.out.println("");
}
}
增强类:
package com.sxt.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import com.sxt.exception.MyException;
/**
* 增强类
*/
public class MyAdvice {
public void beforeAdvice() {
System.out.println("前置增强");
}
public void afterAdvice() {
System.out.println("后置增强");
}
public void roundAdvice(ProceedingJoinPoint pjp) {
beforeAdvice();
// 获取参数
Object[] args = pjp.getArgs();
// 增强的目标方法
Object target = pjp.getTarget();
try {
Object proceed = pjp.proceed();
afterAdvice();
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 可以做异常拦截
*/
public void exceptionAdvice(Throwable tx) {
if (tx instanceof MyException) {
MyException myException = (MyException) tx;
System.out.println(myException.getCode());
System.out.println(myException.getMsg());
return;
}
System.out.println(tx);
System.out.println("异常增强");
}
}
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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置增强的目标 -->
<bean id="targetClass" class="com.sxt.target.impl.TargetClassImpl"></bean>
<!-- 具体增强类对象 -->
<bean id="myAdvice" class="com.sxt.advice.MyAdvice"></bean>
<!--
织入: 将切点 和 具体增强类结合
-->
<!-- 进行AOP配置 -->
<aop:config>
<!-- 配置增强对象 -->
<aop:aspect ref="myAdvice">
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.sxt.target.impl.*.*(..))" id="pointcut"/>
<!-- 配置增强对象中方法 前置增强 -->
<!-- <aop:before method="beforeAdvice" pointcut-ref="pointcut" /> -->
<!-- 后置增强 -->
<!-- <aop:after method="afterAdvice" pointcut-ref="pointcut"/> -->
<!-- 环绕增强 -->
<!-- <aop:around method="roundAdvice" pointcut-ref="pointcut"/> -->
<!-- 异常增强 -->
<aop:after-throwing method="exceptionAdvice" pointcut-ref="pointcut" throwing="tx"/>
</aop:aspect>
</aop:config>
</beans>
Spring-Aop 配置方式:注解
增强类:
package com.sxt.advice;
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.springframework.stereotype.Component;
import com.sxt.exception.MyException;
/**
* 增强类
*/
@Component
@Aspect
public class MyAdvice {
// @Before("execution(* com.sxt.target.impl.*.*(..))")
public void beforeAdvice() {
System.out.println(this);
System.out.println("前置增强");
}
/**
* @AfterReturning 可以拿到 目标方法的返回值
* @After 只能后置增强的效果
*/
@AfterReturning(value="execution(* com.sxt.target.impl.*.*(..))",returning = "rs")
public void afterAdvice(Object rs) {
System.out.println(rs);
System.out.println("后置增强");
}
// execution(* 包名.类.方法(..) ..:表示任意参数
// @Around("execution(* com.sxt.target.impl.*.*(..))")
public void roundAdvice(ProceedingJoinPoint pjp) {
beforeAdvice();
// 获取参数
Object[] args = pjp.getArgs();
// 增强的目标方法
Object target = pjp.getTarget();
try {
Object proceed = pjp.proceed();
//afterAdvice();
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 可以做异常拦截
*/
// @AfterThrowing( value="execution(* com.sxt.target.impl.*.*(..))",throwing = "tx")
public void exceptionAdvice(Throwable tx) {
if(tx instanceof MyException) {
MyException myException = (MyException) tx;
System.out.println(myException.getCode());
System.out.println(myException.getMsg());
return ;
}
System.out.println(tx);
System.out.println("异常增强");
}
}
目标类:
package com.sxt.target.impl;
import org.springframework.stereotype.Component;
import com.sxt.exception.MyException;
import com.sxt.target.IUserDao;
@Component
public class UserDaoImpl implements IUserDao {
@Override
public int sing() {
//throw new MyException("4001001", "自己定义的异常");
System.out.println(" 月亮代表我的心 ");
return 10;
}
}
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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描组件 -->
<context:component-scan base-package="com.sxt"></context:component-scan>
<!-- 开启注解式 增强的通知
proxy-target-class 使用cglib 创建代理对象
1. UserDao 创建代理对象
2. 增强类绑定
默认是JDK 的代理动态代理 === UserDaoImpl 代理类
-->
<aop:aspectj-autoproxy proxy-target-class="true" ></aop:aspectj-autoproxy>
</beans>
总结
IoC/DI和AOP
IoC : 控制反转
对于整个应用而言,创建对象的权利,从应用自身创建移交给了Spring容器.对象的创建的权利发生转向.所以被称之为控制反转.
DI : 依赖注入
在研究控制反转时,发现其实反转的内容主要只,对象创建和对象注入.且对象的创建存在依赖关系.所以,控制反转其实更具体就是注入对象.所以被称之为DI.
控制反转和依赖注入本质上一样的,但是角度不同.站在应用的角度,是控制反转,站在Spring容器的角度上,是依赖注入.
创建对象
创建对象的方式:
- 构造方法(默认方式)
- 静态工厂:通过静态方法创建对象
- 非静态工厂:非静态方法创建对象
- 注解
属性注入:
-
构造方法
-
set方法
-
注解
常用的注入方式:
使用set方法注入: 因为set方法可以根据需要的属性进行注入,而构造方法依赖构造器.必须要有set方法.
注解(最常用),一般只能用于自己定义的代码.在源码中无法使用注解.
IOC常用注解:
@Component : 组件 被该注解注释的类, 会创建对象对象放入到IOC容器
@Controller : 表示控制层 被该注解注释的类, 会创建对象对象放入到IOC容器
@Service : 表示Service 层 被该注解注释的类, 会创建对象对象放入到IOC容器
@Repository : 表示持久化层 被该注解注释的类, 会创建对象对象放入到IOC容器
@Autowired : 自动装配 默认type装配
@Qualifier(名称) : 使用指定的名称装配对象
注意:
标准化.
标准化,在开发中,在流程上会结构清晰,条理分明.代码可读性提高了.
在维护上,定位问题相对快准确,扩展程序相对轻松