标签:load attr 情况下 for listen 解决 持久 work expr
expression.jar
spring-tx.jar
,声明式事务时使用;Servlet是具体的业务功能,不能封装
spring-beans.jar
spring-context.jar
spring-core.jar
spring-expression.jar
commons-logging.jar
applicationContext.xml
文件
applicationContext.xml
中配置的信息最终存储到了 AppliationContext 容器中。.xsd
<?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>
使用:
People.java
的实体类,一般对应数据库中一个表;applicationContext.xml
<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">
<!-- id 是获取该对象的标识,目的是为了以后方便的获取使用该对象; class 表示具体创建的是哪个类对象-->
<bean id="people" class="com.moyue.pojo.People"></bean>
</beans>
getBean(“<bean>标签 id 值”,返回值类型);
如果没有第二个参数, 默认是 Object;getBeanDefinitionNames()
,是Spring 容器中目前管理的所有对象;public class SpringTest {
public static void main(String[] args) {
// 加载配置文件,同时创建对应类
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// 使用 getBean() 创建对象
People people = applicationContext.getBean("people", People.class);
System.out.println("创建的对象名为:" + people + "\n");
// 查看当前 Spring 容器中管理的所有类对象(以及数量)
int beanDefinitionCount = applicationContext.getBeanDefinitionCount();
System.out.println("当前 Spring 容器中管理的类对象数目为:" + beanDefinitionCount + "\n");
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println( "当前 Spring 容器中管理的类对象为:" + beanDefinitionName + "\n");
}
}
}
程序运行结果为:
创建的对象名为:People(id=0, name=null, gender=null, score=0, tel=null)
当前 Spring 容器中管理的类对象数目为:1
当前 Spring 容器中管理的类对象为:people
首先提供一个实体类:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class People {
private Integer id;
private String name;
private String gender;
private Integer score;
private String tel;
}
<bean id = "people" class= "com.moyue.pojo.People"></bean>
public void createObjectByConstructor(){
// 1.启动 spring 容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2.从 spring 容器中取出数据
People people = (People)context.getBean("people");
}
spring只支持两种工厂:实例工厂和静态工厂
实现步骤:
public class PeopleFactory {
public People newInstance() {
return new People(4, "张三", "男", 98,"12323232");
}
}
以前常规的使用工厂创建对象方式:
PeopleFactory factory = new PeopleFactory();
People people = factory.newInstance();
下面是对应的在spring中使用的方式:(factory-bean 对应于 id),即在 applicationContext.xml 中配置
<!--使用实例工厂创建对象-->
<!--首先创建一个工厂-->
<bean id="factory" class="com.moyue.factory.PeopleFactory"></bean>
<!--根据工厂创建对象,factory-bean 对应工厂 id,factory-method 对应创建对象方法-->
<bean id="factoryPeople" factory-bean="factory" factory-method="newInstance"></bean>
spring 容器只负责调用静态工厂方法,而静态工厂方法内存实现需要自己完成;
实现步骤
public class StaticPeopleFactory {
public static People newInstance(){
return new People(5, "李四", "女", 98,"12323232");
}
}
<!--使用静态工厂创建对象-->
<!--不需要创建工厂,直接创建对象,只需要指明工厂类可以直接使用工厂中的方法-->
<bean id="staticFactoryPeople" class="com.moyue.factory.StaticPeopleFactory"
factory-method="newInstance"></bean>
context.getBean
时才要创建对象ApplicationContext context = new ClassPathXmlApplicationContext(“applicationContext.xml”);
时候;代码示例:
public void People(){
public People(){
System.out.println("执行构造函数");
}
}
// 分别放行执行其中一个
<bean id="people" class="com.moyue.pojo.People"></bean>
<bean id="people" lazy-init="false" class="com.moyue.pojo.People"></bean>
<bean id="people" lazy-init="true" class="com.moyue.pojo.People"></bean>
测试函数为:
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
System.out.println("这是分割线");
People people = (People)context.getBean("people");
}
}
测试结果为:
// 下面是上面挨个放行之后执行的结果集
执行构造函数
这是分割线
执行构造函数
这是分割线
这是分割线
执行构造函数
<!--默认值或者设置为 singleton 都表示产生的对象是单例的-->
<bean id="people" scope="singleton" class="com.moyue.pojo.People"></bean>
<!--prototype 表示多例模式-->
<bean id="people" scope="prototype" class="com.moyue.pojo.People"></bean>
测试文件
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
People people1 = (People)context.getBean("people");
People people2 = (People)context.getBean("people");
System.out.println(people1.equals(people2));
}
}
测试结果:
// 使用单例模式时,只执行一次构造函数
执行构造函数
true
// 执行多例模式时,执行两次构造函数
执行构造函数
执行构造函数
false
注:在单例模式下,启动 spring 容器,便会创建对象;在多例模式下,启动容器并不会创建对象,获得 bean 的时候才会创建对象
1、spring容器创建对象
2、执行init方法
3、调用自己的方法
4、当spring容器关闭的时候执行destroy方法
注意:当scope为"prototype"时,调用 close() 方法时是不会调用 destroy 方法的
下面是测试程序:
public class SpringLifeCycle {
public SpringLifeCycle(){
System.out.println("SpringLifeCycle");
}
//定义初始化方法
public void init(){
System.out.println("init...");
}
//定义销毁方法
public void destroy(){
System.out.println("destroy...");
}
public void sayHello(){
System.out.println("say Hello...");
}
}
<bean id="springLifeCycle" init-method="init" destroy-method="destroy"
class="com.moyue.pojo.SpringLifeCycle"></bean>
测试程序:
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
SpringLifeCycle springLifeCycle = (SpringLifeCycle) context.getBean("springLifeCycle");
springLifeCycle.sayHello();
// 销毁 Spring 容器
ClassPathXmlApplicationContext classContext = (ClassPathXmlApplicationContext) context;
classContext.close();
}
}
测试结果:
SpringLifeCycle
init...
say Hello...
destroy...
就是给对象的属性进行赋值
public class People{
public People(){
}
public People(int id, Student student){
this.id = id;
this.student = student;
}
}
Spring 配置环境为:
<!--
index:代表参数的位置,从 0 开始计算;
type:指的是参数的类型,在有多个构造函数的时候使用 type 进行区分,如果可以区分哪一个构造函数就可以不用写 type;
value:给基本类型赋值;
ref:给引用类型赋值;
-->
<bean id = "people" class = "com.moyue.pojo.People">
<constructor-arg index = "0", type = "java.lang.Integer" value = "1"></constructor-arg>
<constructor-arg index = "1", type = "com.moyue.pojo.Student" ref = "student"></constructor-arg>
</bean>
<bean id = "student" class = "com.moyue.pojo.Student"></bean>
测试:利用构造函数进行赋值
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
People people = (People) context.getBean("people");
System.out.println(people.getId());
总结:
1、如果spring的配置文件中的bean中没有
2、如果spring的配置文件中的bean中有
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class People {
private Integer id;
private String name;
private String gender;
private Integer score;
private String tel;
private List<String> list;
private Map<String, String> map;
private Set<String> set;
private String[] string;
private Properties properties;
private Student student;
}
<bean id="people" class="com.moyue.pojo.People">
<property name="id" value="12"></property>
<property name="name" value="chenliu"></property>
<property name="gender" value="女" ></property>
<property name="score" value="13"></property>
<property name="tel" value="123243"></property>
</bean>
上面代码等效于:(一般使用上面方式)
<bean id="peo" class="com.moyue.pojo.People">
<property name="id">
<value>12</value>
</property>
<property name="name">
<value>chenliu</value>
</property>
<!-- 。。。。。。-->
</bean>
Set<?>
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
</set>
</property>
List<?>
<property name="list">
<list>
<!--虽然这里存放 String 数据类型,但是值不使用 ""-->
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="list" value="1">
</property>
<property name="strs" >
<array>
<value>1</value>
<value>2</value>
<value>3</value>
</array>
</property>
map<key, value>
以及对象类型<property name="map">
<map>
<entry key="a" value="b"></entry>
<entry key="c" value="d"></entry>
<entry key="d">
<ref bean="student"/>
</entry>
</map>
</property>
备注:引用上面的 student,需要同时配置
<bean id = student class = "com.moyue.pojo.Student"></bean>
<property name="demo">
<props>
<prop key="key">value</prop>
<prop key="key1">value1</prop>
</props>
</property>
spring 动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个 Connection 是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的。
简单来说什么是依赖注入,就是给属性赋值(包括基本数据类型和引用数据类型)
public class A{
int id;
string name;
private B b;
}
public class B{
int score;
}
代码体现:
// 先对 A 对象进行实例化
<bean id="a" class="com.moyue.pojo.A">
<property name="b" ref="b"></property> </bean>
// 然后对 A 类中的 B 对象进行实例化
<bean id="b" class="com.moyue.pojo.B">
<property name="id" value="1"></property>
<property name="price" value="12"></property>
</bean>
asm-3.3.1.jar
cglib-2.2.2.jar
commons-logging-1.1.1.jar
commons-logging-1.1.3.jar
javassist-3.17.1-GA.jar
jstl-1.2.jar
LIST.TXT
log4j-1.2.17.jar
log4j-api-2.0-rc1.jar
log4j-core-2.0-rc1.jar
mybatis-3.2.7.jar
mybatis-spring-1.2.3.jar
mysql-connector-java-5.1.30.jar
slf4j-api-1.7.5.jar
slf4j-log4j12-1.7.5.jar
spring-aop-4.1.6.RELEASE.jar
spring-beans-4.1.6.RELEASE.jar
spring-context-4.1.6.RELEASE.jar
spring-core-4.1.6.RELEASE.jar
spring-expression-4.1.6.RELEASE.jar
spring-jdbc-4.1.6.RELEASE.jar
spring-tx-4.1.6.RELEASE.jar
spring-web-4.1.6.RELEASE.jar
standard-1.1.2.jar
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--上下文参数,配置 Spring 配置文件位置,告诉 Tomcat 启动时候加载 Spring 配置文件路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- Spring 配置文件目录-->
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--内部封装了一个监听器,用于帮助加载 Spring 配置文件-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
<?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-be ans.xsd">
<!-- 数据源封装类 .数据源:获取数据库连接,spring-jdbc.jar 中(类名知道即可),代替类MyBatis中的dataSource配置功能-->
<bean id="dataSouce" class="org.springframework.jdbc.datasource.DriverMana gerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"> </property>
<property name="url" value="jdbc:mysql://localhost:3306/ssm"> </property>
<property name="username" value="root"></property>
<property name="password" value="smallming"></property>
</bean>
<!-- 创建SqlSessionFactory 对象-->
<!--这个类是专门在 Spring 中生成 sqlSessionFactory 对象的类-->
<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接信息来源于dataSource -->
<property name="dataSource" ref="dataSouce"></property>
</bean>
<!-- 扫描器相当于mybatis.xml 中mappers 下package 标签,扫描com.moyue.mapper 包后会给对应接口创建对象-->
<bean
class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 要扫描哪个包-->
<property name="basePackage" value="com.moyue.mapper"></property>
<!-- 和factory 产生关系-->
<property name="sqlSessionFactory" ref="factory"></property>
</bean>
<!-- 由spring 管理service 实现类-->
<bean id="airportService"
class="com.moyue.service.impl.AirportServiceImpl">
<property name="airportMapper" ref="airportMapper"></property>
</bean>
</beans>
@WebServlet("/airport")
public class AirportServlet extends HttpServlet{
private AirportService airportService;
@Override
public void init() throws ServletException {
// 对service 实例化
// ApplicationContext ac = new
ClassPathXmlApplicationContext("applicationContext.xm l");
// spring 和web 整合后所有信息都存放在webApplicationContext
// 下面语句作用:因为现在在web.xml中配置spring配置文件,也就是说当Tomcat 启动后会将spring配置文件中所有东西启动,启动完成之后会把信息放在webApplicationContext容器中,下面是往外取东西
ApplicationContext ac = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
airportService=ac.getBean("airportService",AirportServiceImpl.class);
}
@Override
protected void service(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException {
req.setAttribute("list", airportService.show());
req.getRequestDispatcher("index.jsp").forward(req,resp);
}
}
Annotation(注解) 是 JDK1.5 及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以 @注解名
在代码中存在的。
前面的 IOC 和 DI 都是通过 xml 文件来进行配置的,我们发现 xml 配置还是比较麻烦的,那么如何简化配置呢?答案就是使用注解!
实体类:People.java(属于包:com.moyue.annotation)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class People(){
private integer id;
private String name;
private String gender;
}
不使用注解的配置方式是:<bean id = "people" class = "com.moyue.pojo.People></bean>
使用注解的步骤:
<context:标签名>
)xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
<context:component-scan base-package = "com.moyue.annotation"></context:component-scan>
,这里使用 base-package:表示含有注解类的包名,如果需要扫描多个包,则上面的代码需要书写多行改变 base-package 里面内容即可;
@Component
public class People{
private Integer id;
private String name;
private String gender;
}
测试程序
@test
public void annotationTest(){
// 启动 Spring 容器;从 Spring 容器中取出数据;通过对象调用方法;
ApplicationContext context = new ClassPathXmlApplicationContext(applicationContext.xml);
People people = (People)context.getBean("people");
System.out.println(people.getId());
}
注: 如果@Component 后面没有参数,则 getBean();中使用该类的类型首字母小写即可;
即上面的等价于:
<bean id = "people" class = "com.moyue.annotation.People">
如果后面有参数,例:@Component(“dd”),相当于上面的 id 等于 dd;
下面的三个注解是@Component 的衍生注解,功能是一样的,只是对应的层不同;
@Resource 注解,可以对类成员变量、方法及其构造方法进行标注,完成自动装配工作。即可以用来消除 set、get 方法;
代码示例:
包 com.moyue.annotation 中有两个类:Student 和 People 类;
public class Student{
pubic void descStudent(){
System.out.println("执行 descStudent()");
}
}
public class People{
private Student student;
public void showStudent(){
this.student.descStudetn();
}
}
如果想要获取 People 对象,同时调用 showStudent()方法:即是给属性 student 进行实例化,即是依赖注入
<property name = "students">
<ref bean = "student">
</property>
<bean id = "student" class = "com.moyue.annotation.Student"></bean>
@Compontent("people")
public class People{
@Resource(name="student")
public Student student;
public void showStudent(){
this.student.descStudent();
}
}
@Compontent("student")
public class Student{
pubic void descStudent(){
System.out.println("执行 descStudent()");
}
}
@Resource注解以后,判断该注解name的属性是否为""(name没有写)
①、如果没有写name属性,则会让属性的名称的值和spring配置文件bean中ID的值做匹配(如果没有进行配置,也和注解@Component进行匹配),如果匹配成功则赋值,如果匹配不成功,则会按照spring配置文件class类型进行匹配,如果匹配不成功,则报错
②、如果有name属性,则会按照name属性的值和spring的bean中ID进行匹配,匹配成功,则赋值,不成功则报错
功能和注解 @Resource 一样,可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。只不过注解@Resource 是按照名称来进行装配,而@Autowired 则是按照类型来进行装配;
public interface PeopleDao{
public void savePeople();
}
@Component("peopleDaoImpl")
public class PeopleDaoImpl implements PeopleDao{
@Override
public void savePeople(){
System.out.println("save People");
}
}
@Service("peopleService")
public class PeopleService(){
@Autowired
private PeopleDao peopleDao;
public void savePeople(){
this.peopleDao.savePeople();
}
}
注意:这里我们在 private PeopleDao peopleDao 上面添加了注解 @Autowired,它首先会根据类型去匹配,PeopleDao 是一个接口,它的实现类是 PeopleDaoImp,那么这里的意思就是:
PeopleDao peopleDao = new PeopleDaoImp();
如果 PeopleDao 的实现类有多个呢?我们创建第一个实现类 PeopleDaoImpTwo
@Component("personDaoImplTwo")
public class PersonDaoImplTwo implements PersonDao{
@Override
public void savePerson() {
System.out.println("save Person Two");
}
}
方法一:更改对象名称:改为:private PeopleDao peopleDaoImpl
,因为 @Autowired 注解默认是按照类型进行匹配,如果类型匹配有多个,则按照名称匹配,这里就是将名称改为 实现类 PeopleDaoImpl 的@Component 中的值;
方法二:配合@Qualifier(“名称”) 使用
即在@Autowird 下面增加一行:@Qualifier("peopleDaoImpl")
,参数值为对应实现类 @Component 中的值;
在使用@Autowired时,首先在容器中查询对应类型的bean
如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
如果查询的结果不止一个,那么@Autowired会根据名称来查找。
如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false
概念:在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面过程就叫做面向切面编程.
AOP 和 Filter 区别
两者的拦截对象不同;
Filter 拦截的是请求;
主要可以在程序执行的任意一个方法的前面或者后面额外添加或者扩充一些功能;
pointcut
;beforeAdvice
afterAdvice
throwsadvice
方式一:Schema-based
implement MethodBeforeAdvice
或者 implement AfterReturningAdvice
)<aop:config>
配置方式二: AspectJ
<aop:config>
的子标签 <aop:aspect>
中配置【在切点方法之前和之后分别执行了一个方法】
步骤一:首先导入 jar,除了 spring 核心功能包外,注意添加两个额外的包:aopalliance.jar 和 aspectjweaver.jar
// 前置通知类实现 MethodBeforeAdvice 接口
public class MyBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("执行前置通知");
}
}
public class MyAfterAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("执行后置通知");
}
}
<bean>
*
为通配符,匹配任意方法名,任意类名,任意一级包名(..)
,就是下面 expression中的最后demo2(..)<aop:pointcut expression="execution(* com.moyue.test.*.*(..))" id="mypoint"/>
表示test 这个包下面的任意类的任意方法的任意参数都需要形成切面,本质上任意位置都可以使用 * 表示任意;
==下面 代码中直接配置 bean,但是方法中并没有 return 对象,能够实例化对象吗?==
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--需要在上面导入 AOP 命名空间-->
<!--首先配置通知类对象,在切面中进行引入-->
<bean id="myBefore" class="com.moyue.advice.MyBeforeAdvice"></bean>
<bean id="myAfter" class="com.moyue.advice.MyAfterAdvice"></bean>
<!--然后配置切面-->
<aop:config>
<!--配置切点,里面的路径是该方法的完整路径(包括参数)-->
<aop:pointcut id="mypoint"
expression="execution(* com.moyue.pointcut.AOPpointcut.AopPointcut())"/>
<!--为切面添加通知,pointcut-ref 为切点的 id-->
<aop:advisor advice-ref="myBefore" pointcut-ref="mypoint"></aop:advisor>
<aop:advisor advice-ref="myAfter" pointcut-ref="mypoint"></aop:advisor>
</aop:config>
<bean id = "pointcut" class="com.moyue.pointcut.AOPpointcut"></bean>
</beans>
public class AOPTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AOPpointcut pointcut = applicationContext.getBean("pointcut", AOPpointcut.class);
pointcut.AopPointcut();
}
}
执行前置通知
这是切点
执行后置通知
实现步骤:
public class MyThrowAdvice {
public void MyException(Exception e){
System.out.println("执行异常通知" + e.getMessage());
}
}
<aop:aspect>
的 ref 属性表示:方法在哪个类中.<aop: xxxx/>
XXX表示什么通知 <!--配置异常通知-->
<bean id="exceptionAdvice" class="com.moyue.exception.MyThrowAdvice"></bean>
<aop:config>
<!-- 这里 ref 告诉 spring,这个 method 是哪一个类的,同时上面也要配 bean -->
<aop:aspect ref="exceptionAdvice">
<aop:pointcut id="mypoint"
expression="execution(* com.moyue.pointcut.AOPpointcut.AopPointcut())"/>
<!-- 这里的 method 是当告诉 spring,触发异常的时候调用的是哪一个方法,后面是针对于哪一个切点的;最后的 throwing 值为上面声明中的异常名-->
<aop:after-throwing method="MyException" pointcut-ref="mypoint"
throwing="e"></aop:after-throwing>
</aop:aspect>
</aop:config>
如果不在这里面声明通知的话,另一种方式是:
在Test类中,通过getBean获取对象,然后通过对象调用方法的时候使用 try-catch,在上面的类中使用 throws抛出,不能使用 try-catch,否则spring接收不到异常
public class MyThrow implements ThrowsAdvice{
public void afterThrowing(Method m, Object[] args,Object target, Exception ex) {
System.out.println("执行异常通知");
}
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("执行异常通过-schema-base 方式");
}
}
<bean id="demo" class="com.moyue.test.Demo"></bean>
<bean id="mythrow" class="com.moyue.advice.MyThrow"></bean>
<aop:config>
<aop:pointcut expression="execution(*com.moyue.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="mythrow" pointcut-ref="mypoint" />
</aop:config>
实现步骤
public class MyArround implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation arg0) throws Throwable {
System.out.println("环绕-前置");
//放行,调用切点方式,语句前就相当于前置通知,语句后为后置通知
Object result = arg0.proceed();
System.out.println("环绕-后置");
return result;
}
}
<bean id="demo" class="com.moyue.test.Demo"></bean>
<bean id="myarround" class="com.moyue.advice.MyArround"></bean>
<aop:config>
<aop:pointcut expression="execution(*com.moyue.test.Demo.demo1())" id="mypoint"/>
<aop:advisor advice-ref="myarround" pointcut-ref="mypoint" />
</aop:config>
public class MyAdvice {
public void mybefore(String name1,int age1){
System.out.println("前置"+name1 );
}
public void mybefore1(String name1){
System.out.println("前置:"+name1);
}
public void myaftering(){
System.out.println("后置2");
}
public void myafter(){
System.out.println("后置1");
}
public void mythrow(){
System.out.println("异常");
}
public Object myarround(ProceedingJoinPoint p) throws Throwable{
System.out.println("执行环绕");
System.out.println("环绕-前置");
Object result = p.proceed();
System.out.println("环绕后置");
return result;
}
}
<aop:after/>
后置通知,是否出现异常都执行<aop:after-returing/>
后置通知,只有当切点正确执行时执行<aop:after/>
和 <aop:after-returing/>
和<aop:after-throwing/>
执行顺序都和在 Spring 配置文件中的配置顺序有关execution()
括号不能扩上 args<aop:before/> arg-names=” 名 称 ”
名 称 来 源 于 expression=”” 中 args(),名称必须一样arg-names=””
里面名称必须和通知方法参数名对应<aop:config>
<aop:aspect ref="myadvice">
<!-- 这里的name1 和 age1 仅仅是对参数进行赋值,然后将这些值赋值给通知,因此上面 advice 参数名称和他们相同-->
<aop:pointcut expression="execution(* com.moyue.test.Demo.demo1(String,int)) and args(name1,age1)" id="mypoint"/>
<aop:pointcut expression="execution(* com.moyue.test.Demo.demo1(String)) and args(name1)" id="mypoint1"/>
<aop:before method="mybefore"pointcut-ref="mypoint" arg-names="name1,age1"/>
<aop:before method="mybefore1" pointcut-ref="mypoint1" arg-names="name1"/>
<aop:after method="myafter" pointcut-ref="mypoint"/>
<aop:after-returning method="myaftering" pointcutref="mypoint"/>
<aop:after-throwing method="mythrow" pointcutref="mypoint"/>
<aop:around method="myarround" pointcut-ref="mypoint"/>
</aop:aspect>
</aop:config>
xmlns:context="http://www.springframework.org/schema/context"
xsi:http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean/>
<bean id=””/>
实现步骤:
<context:component-scan base-package="com.moyue.advice,com.moyue.test"></context:component-scan>
同时要添加动态代理: proxy-target-class值为 true表示使用 cglib动态代理,值为 false 表示使用 jdk 动态代理;
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
@Component("dd")
public class Demo {
@Pointcut("execution(* com.moyue.test.Demo.demo1())")
public void demo1() throws Exception{
// int i = 5/0;
System.out.println("demo1");
}
}
@Component
@Aspect // 表示该类为通知切面类
public class MyAdvice {
@Before("com.moyue.test.Demo.demo1()")
public void mybefore(){
System.out.println("前置");
}
@After("com.moyue.test.Demo.demo1()")
public void myafter(){
System.out.println("后置通知");
}
@AfterThrowing("com.moyue.test.Demo.demo1()")
public void mythrow(){
System.out.println("异常通知");
}
@Around("com.moyue.test.Demo.demo1()")
public Object myarround(ProceedingJoinPoint p) throws Throwable{
System.out.println("环绕-前置");
Object result = p.proceed();
System.out.println("环绕-后置");
return result;
}
}
下面是AOP底层原理
设计模式:前人总结的一套解决特定问题的代码.
为了解决静态代理频繁编写代理功能缺点
JDK 动态代理
优点:jdk 自带,不需要额外导入 jar
使用 JDK 动态代理时可能出现下面异常
出现原因:希望把接口对象转换为具体真实对象
cglib 动态代理
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
<property/>
两种配置办法
<bean>
中通过 autowire=””
配置,只对这个 <bean>
生效;<beans>
中通过 default-autowire=””
配置,表示当前文件中所有 <bean>
都生效,是全局配置内容;参数配置
default-autowire=””
值。默认全局和局部都没有配置情况下,相当于 no;<bean>
,否则不能根据类型注入;<bean>
的 id相同;代码示例:
public class Teacher{
}
public class People{
private Teacher teacher;
public Teacher getTeacher(){
return teacher;
}
public void setTeacher(Teacher teacher){
this.teacher = teacher;
}
}
原来 Spring 中的配置文件写法
<bean id = "techer" class = "com.moyue.Teacher"> </bean>
<bean id = "people" class = "com.moyue.People">
<property name = "teacher" ref = "teacher">
</bean>
使用自动注解的写法:
<bean id = "techer" class = "com.moyue.Teacher"> </bean>
<!--其中 XXX 为上面的选项之一,只要能唯一确定即可-->
<bean id = "people" class = "com.moyue.People" autowire = "XXX"> </bean>
将一些配置写在 properties 属性文件中,然后使用 Spring 进行加载读取;
properties 文件中的后面的值中间不能有空格
<context:property-placeholder location="classpath:db.properties", location="classpath:abc.properties"/>
对应的 db.properties 配置示例为:
jdbc.driverClassName = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/lianxi
jdbc.username = root
jdbc.password = GJXAIOU
然后对于其中的属性值,可以spring在配置文件的 bean :id= DataSource中的value= ${key}取值
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
原来的直接在 Spring 配置的配置方式:
<bean id = "dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/lianxi"></property>
<property name="username" value="root"></property>
<property name="password" value="GJXAIOU"></property>
</bean>
default-sutowire = "byName"
开启自动注入的时候,当同时使用 扫描器的时候;
<!-- 扫描器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.moyue.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="factory"></property> </bean>
下面被 Spring 管理的类使用注解,首先需要在 Spring 中使用
在被Spring 管理的类中通过 @Value(“${key}”)
取出properties 中内容,就不需要全部在Spring配置文件中使用 value= “${}”
进行取值;Servlet 没有被 Spring 容器管理
<context:property-placeholder location="classpath:second.properties"/>
<context:component-scan base-package="com.moyue.service.impl">
</context:component-scan>
package com.moyue.service.impl
@service
public class Demo{
@Value("${my.demo}")
private String test;
// 引用对象的时候
@Resource
private UserMapper userMapper;
}
my.demo = 123
scope 是 <bean>
的属性,作用:控制对象有效范围(例如单例,多例等)
<bean/>
标签对应的对象默认是单例的;即bean声明一次之后,在类中即使使用getBean多次,但是最终对象是同一个。
无论获取多少次,都是同一个对象(单例就是多次获取某一个对象的时候,不是每次都实例化)
作用: 在应用程序中保证最多只能有一个实例;
对象只有被调用时才去创建,同时由于添加了锁,所以导致效率低
示例代码
public class SingleTon {
//由于对象需要被静态方法调用,因此把方法 getInstance 设置为static
//由于对象是static,必须要设置访问权限修饰符为private ,
如果是public 可以直接调用对象,不执行访问入口
private static SingleTon singleton;
/** 单例设计模式首先要求其构造方法的私有化,这样其他类不能实例化这
个类对象,同时需要对外提供提供入口
*/
private SingleTon(){}
// 实例方法,实例方法必须通过对象调用,因此需要设置方法为静态方法,才能调用
public static SingleTon getInstance(){
// 添加逻辑如果实例化过,直接返回
if(singleton==null){
/*
* 多线程访问下,可能出现if 同时成立的情况(同时
执行到if语句),需要添加锁*/
synchronized (SingleTon.class) {
//双重验证
if(singleton==null){
singleton = new SingleTon();
}
}
}
return singleton;
}
}
测试方法(使用方法)
public class Test{
public static void main(){
SingleTon singleTon1 = singleTon.getInstance();
SingleTon singleTon12= singleTon.getInstance();
System.out.println(singleTon1 == singleTon2);
}
}
// output:true
注:构造方法特征方法名和类名相同且无返回值, 因为它必须返回当前对象的引用,所以没有返回值;
解决了懒汉式中多线程访问可能出现同一个对象和效率低问题
public class SingleTon {
//在类加载时进行实例化.
private static SingleTon singleton=new SingleTon();
private SingleTon(){}
public static SingleTon getInstance(){
return singleton;
}
}
声明式事务:
事务控制代码已经由 spring 写好,程序员只需要声明出哪些方法需要进行事务控制和如何进行事务控制然后 Spring 会帮助我们管理;
事务管理器基于通知(advice)的,即本质上就是通知;
在 spring 配置文件中配置声明式事务
需要引入 tx 命名空间
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
因此配置文件 applicationContext.xml 中的内容为:
<context:property-placeholder location="classpath:db.properties,classpath:second.properties"/>
<!-- 因为事务最终都是要提交给数据库的,因此需要 DataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverMa nagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 通知类在spring-jdbc.jar 中 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSour
ceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置声明式事务,确认具体哪些方法有事务 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 哪些方法需要有事务控制 -->
<!-- 名字里面可以是用 *,表示方法以ins 开头事务管理 -->
<tx:method name="ins*" />
<tx:method name="del*" />
<tx:method name="upd*" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<!--切点范围设置大一些,仅仅设置哪些有切点即可,和事务控制没有关系 -->
<aop:pointcut expression="execution(* com.moyue.service.impl.*.*(..))"
id="mypoint" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" />
</aop:config>
使用:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@toString
public class People{
int id;
String username;
String password;
}
public interface UsersService{
int insert(Users user);
}
public class UsersServiceImpl implements UsersService{
@override
// 声明式事务是基于通知的,要将下面的方法实现事务,要配置其切点
public int insert(Users users){
return 0;
}
}
==对应的注解方式:== @Transactional
https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html
name=””
表示哪些方法需要有事务控制
支持*通配符
readonly=”boolean”
表示是否是只读事务.
REQUIRED (默认值): (针对被调用的)如果当前有事务,就在事务中执行,如果当前没有事务,新建一个事务.
SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行.
MANDATORY:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务,报错.
NOT_SUPPORTED:必须在非事务下执行,如果当前没有事务,正 常执行,如果当前有事务,把当前事务挂起.
NEVER:必须在非事务状态下执行,如果当前没有事务,正常执行,如果当前有事务,报错.
NESTED:必须在事务状态下执行.如果没有事务,新建事务,如果当前有事务,创建一个嵌套事务.
isolation=””
事务隔离级别(4.5开始是其值的可选项)DEFAULT: 默认值,由底层数据库自动判断应该使用什么隔离级别
READ_UNCOMMITTED: 可以读取未提交数据,可能出现脏读,不重复读,幻读.
效率最高.
READ_COMMITTED:只能读取其他事务已提交数据.可以防止脏读,可能出现不可重复读和幻读.
REPEATABLE_READ: 读取的数据会被添加锁,防止其他事务修改此数据,可以防止不可重复读.脏读,可能出现幻读.
rollback-for=”异常类型全限定路径”
表示当出现什么异常时需要进行回滚
no-rollback-for=””
当出现什么异常时不滚回事务.
补充知识
脏读:
一个事务(A)读取到另一个事务(B)中未提交的数据,另一 个事务中数据可能进行了改变,此时A 事务读取的数据可能和数据库中数据是不一致的,此时认为数据是脏数据,读取脏数据过程叫做脏读.
@Component 创建类对象,相当于配置
@Service 与@Component 功能相同.
但是@service写在 ServiceImpl 类上.
@Repository 与@Component 功能相同.
写在数据访问层类上.
@Controller 与@Component 功能相同.
写在控制器类上.
@Value() 获取 properties 文件中内容
@Pointcut() 定义切点
@Aspect() 定义切面类
@Before() 前置通知
@After 后置通知
@AfterReturning 后置通知,必须切点正确执行
@AfterThrowing 异常通知
@Arround 环绕通知
使用Ajax绝不会有跳转语句,都是写的输出语句,即响应回来的结果是什么
ajax:异步请求.【有请求的时候,浏览器开启一个子线程进行数据请求,获取到数据之后,根据脚本对主线程中东西进行修改,主线程在子线程进行请求的过程中是不发生改变的;】
示例代码
url: 请求服务器地址
data:请求参数
dataType:服务器返回数据类型
error 请求出错执行的功能
success 请求成功执行的功能,表达式function(data)中的
data是服务器返回的数据
type:请求方式
// 这里配置 script type 等等
$(function(){
$("a").click(function(){
$.ajax({
url:'demo',
data:{"name":"张三"},
dataType:'html',
error:function(){
alert("请求出错.")
},
success:function(data){
alert("请求成功"+data)
},
type:'POST'
});
return false;
})
});
{“key”:value,”key”:value}
[{“key”:value,”key”:value},{}]
标签:load attr 情况下 for listen 解决 持久 work expr
原文地址:https://www.cnblogs.com/qq438649499/p/12128966.html