Spring是整合多个框架的主流架构;
Spring有两个目标,一是让现有技术更易于使用,二是养成良好的编程习惯;
AOP:面向切面编程
IoC:控制反转
DI:依赖注入
一、实现配置文件输入什么,控制台输出什么
首先创建一个java工程,Spring42;1、新建lib文件夹,引入jar包;2、创建源文件引入log4j和applicationContext;3、xml引入头文件
applicationContext:
头文件
<?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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
</beans>
4、建立helloSpring包,建立HelloSpring类
5、在applicationContext中编写配置文件
applicationContext
<!-- name定义小名,测试时候getBean小名,也能执行 -->
<bean id="hello" class="cn.bdqn.ioc.helloSpring.HelloSpring" name="h1,h2,h3">
<!-- 注入 ,java反射动态获取的set方法,设置属性519-->
<property name="who">
<value>韩梅梅</value>
</property>
</bean>
HelloSpring:
package cn.bdqn.ioc.helloSpring;
public class HelloSpring {
private String who;
public void print(){
System.out.println("hello:"+getWho());
}
public String getWho() {
return who;
}
public void setWho(String who) {
this.who = who;
}
}
HelloSpringTest:
package cn.bdqn.ioc.helloSpring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloSpringTest {
@Test
public void test1(){
//1.加载Spring的配置文件,实例化Spring的上下文,此处就是控制权的反转
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过getBean的方法来获取指定<Bean>中id的实例
HelloSpring hs = (HelloSpring)context.getBean("h3");
hs.print();
}
}
以上代码实现控制反转输出hello,韩梅梅
二、什么是控制反转和依赖注入?
IoC是什么?IoC(Inversion of Control) – 控制反转。它不是一种技术,而是一种思想。要理解什么是控制反转。那么我们就要理解“是谁控制谁呢,为什么是反转呢”。
是谁控制谁:在传统的Java SE程序设计,我们要使用对象要在对象内通过new来创建,即应用程序主动创建依赖对象。而IoC是一个专门创建依赖对象的容器。即容器控制对象。
为什么是反转:因为IoC帮我们创建并注入依赖对象,对象只是被动地接受依赖对象(传统的是在对象内通过new来主动地创建依赖对象),所以是反转。即从主动获取依赖对象到被动接受依赖对象的反转!
2. DI是什么?
DI(Dependency Injection) – 依赖注入。在程序运行期间,容器动态地将依赖关系注入到组件中。要更好地了解DI,我们需要理解以下几点:
1、谁依赖谁:应用程序依赖于IoC容器;
2、为什么依赖:应用程序需要IoC容器提供外部资源;
3、谁注入谁:IoC容器向应用程序注入;
4、注入什么:IoC向应用程序注入外部资源,数据等。两者什么关系?
IoC和DI其实是同一概念的不同描述。由于IoC(控制反转)不好了解,所以在2004年,Martin Fowler给出了一个新的名称:“依赖注入”。“依赖注入”可以让人们更好地关注到依赖对象和注入这两个重要的东西。三、练习,输出A说111,B说222
applicationContext:
<bean id="zhangga" class="cn.bdqn.ioc.helloSpring.LianXiSpring">
<!-- 注入 ,java反射动态获取的set方法,设置属性519-->
<property name="who">
<value>张嘎</value>
</property>
<property name="say">
<value>111</value>
</property>
</bean>
<bean id="Rod" class="cn.bdqn.ioc.helloSpring.LianXiSpring">
<!-- 注入 ,java反射动态获取的set方法,设置属性519-->
<property name="who">
<value>Rod</value>
</property>
<property name="say">
<value>222</value>
</property>
</bean>
LianXiSpring: ```java package cn.bdqn.ioc.helloSpring;
public class LianXiSpring { private String who; private String say;
public void print(){
System.out.println(getWho()+"说"+getSay());
}
public String getWho() {
return who;
}
public void setWho(String who) {
this.who = who;
}
public String getSay() {
return say;
}
public void setSay(String say) {
this.say = say;
}
}
Test:
```java
package cn.bdqn.ioc.helloSpring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class LianXiTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
LianXiSpring zhang = (LianXiSpring)context.getBean("zhangga");
LianXiSpring Rod = (LianXiSpring)context.getBean("Rod");
zhang.print();
Rod.print();
}
}
四、认识AOP
1、AOP是面向切面编程,是面向对象的有益补充
2、切面:这些穿插在既定业务中的操作就是所谓的“横切逻辑”
3、面向切面编程:简单地说是在不改变原有程序的基础上为代码段增加新的功能,对其进行增强处理。设计思想来源于代理模式;
4、增强处理就是在方法前后增加输出
5、关键词
切面:Aspect—横切关注点
连接点:JoinPoint—-写增强的参数,具体执行点
增强处理:Advice——-切面在某个特定连接点上执行的代码逻辑
切入点:Pointcut——-对连接点的特征进行描述
目标对象:Target object——-被一个或多个切面增强的对象,即被增强对象
AOP代理:AOPproxy—-由AOP框架所创建的对象,实现执行增强处理方法等功能
织入:Weaving——-将增强处理连接到应用程序中的类型或对象上的过程
6、前置增强
(1)、创建service和dao包,分别创建Impl接口
(2)、在UserServiceImpl下,建立属性,再去Spring IOC注入
(3)、注入和在addUser前后插入日志信息,建立logger包和MyLogger类
applicationContext
<bean id="userDao" class="cn.bdqn.aop.dao.Impl.UserDaoImpl"></bean>
<bean id="userService" class="cn.bdqn.aop.service.Impl.UserServiceImpl">
<!-- name属性名 ref对象519-->
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 前后插入日志 519-->
<bean id="myLogger" class="cn.bdqn.aop.logger.MyLogger"></bean>
<aop:config>
<!-- 定义切点 -->
<aop:pointcut expression="execution(* cn.bdqn.aop.service..*.*(..))" id="pointcut"/>
<!-- 定义切面(切面等于切点加上增强方法) -->
<aop:aspect ref="myLogger">
<!-- 增强方式(前置,后置) -->
<!-- 前置增强 ,此处的方法名和myLogger中匹配的上就行-->
<aop:before method="before" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
//UserDao
package cn.bdqn.aop.dao;
public interface UserDao {
public void addUser();
}
//UserDaoImpl
package cn.bdqn.aop.dao.Impl;
import cn.bdqn.aop.dao.UserDao;
public class UserDaoImpl implements UserDao{
public void addUser(){
System.out.println("---添加用户---");
}
}
//UserService
package cn.bdqn.aop.service;
public interface UserService {
public void addUser();
}
//UserServiceImpl
package cn.bdqn.aop.service.Impl;
import cn.bdqn.aop.dao.UserDao;
import cn.bdqn.aop.service.UserService;
public class UserServiceImpl implements UserService{
//userDao 通过Spring IOC注入
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
//调用dao层的addUser
public void addUser(){
userDao.addUser();
}
}
//MyLogger类
package cn.bdqn.aop.logger;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
public class MyLogger {
//日志输出
Logger log = Logger.getLogger(MyLogger.class);
//定义代理类---applicationContext.xml
//前置增强 JoinPoint连接点
public void before(JoinPoint jp){
//System.out.println("前置增强");
log.info("调用的"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法");
}
}
//aopTest
package cn.bdqn.aop;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.bdqn.aop.service.UserService;
public class UserTest {
@Test
public void addUser(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us = (UserService)context.getBean("userService");
us.addUser();
}
}
以上则是增强处理
五、代理模式
首先,AOP的底层原理就是java的动态代理机制
有两种动态代理机制1,jdk动态代理;2,cglib动态代理
各有优势:CGLIB 1.需要依赖于第三方jar包
2.不依赖目标类的接口
JDK
1.不需要依赖于第三方jar包
2.目标类必须有相应的接口
执行效率:jdk.6之后,jdk动态代理效率>cglib动态代理
SpringAOP 在目标类有实现接口的时候默认使用是jdk代理,没有实现接口使用cglib;
代码分别实现:
首先在aop下创建代理proxy包
其次创建代理类jdkProxy包—>JDKProxy类;目标类:UserDaoImpl;写完Impl再写代理类
最后测试;
CGLIBProxy的测试方法和上面相同
Jdk代理类
package cn.bdqn.aop.proxy.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
//jdk实现方式 代理类--->实现java反射下的接口,可以看成是中介
public class JDKProxy implements InvocationHandler{
//目标对象---->代理类及方法与目标类及方法建立关联关系
private Object target;
//创建代理类 返回代理对象,参数是目标对象
public Object newProxy(Object obj){
//1.给目标对象赋值
this.target = obj;
//2.通过目标对象获取类加载参数,通过java反射获得
ClassLoader loader = target.getClass().getClassLoader();
//3.通过目标对象获取接口 通过java反射获取
Class<?>[] interfaces = target.getClass().getInterfaces();
//4.最后通过类加载参数和接口初始化代理类
return Proxy.newProxyInstance(loader, interfaces, this);
}
//代理对象想要调用目标方法,所执行的方法名叫invoke
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// invoke
check();
//修改目标方法的参数;传来的参数是李四,在中间执行代码修改,实现输出的是王五
System.out.println(Arrays.toString(args));
if(args[0].toString().equals("李四")){
args[0] = "王五";
}
//method执行目标方法
Object result = method.invoke(target, args);
//修改返回值
result = 100;
return result;
}
private void check(){
//前置增强
System.out.println("---执行检查---");
}
}
UserDaoImpl:
package cn.bdqn.aop.proxy.dao.Impl;
import cn.bdqn.aop.proxy.dao.UserDao;
//目标类
public class UserDaoImpl implements UserDao{
public int addUser(String userName,int age){
System.out.println("添加用户,姓名:"+userName+"年龄:"+age);
return 1;
}
}
别忘记抽接口,抽到UserDao中
Test:
package cn.bdqn.aop.proxy.jdkProxy;
import cn.bdqn.aop.proxy.dao.UserDao;
import cn.bdqn.aop.proxy.dao.Impl.UserDaoImpl;
public class Test {
public static void main(String[] args) {
//1.创建目标对象
UserDaoImpl udi = new UserDaoImpl();
//原来的执行路径
//udi.addUser("张三", 18);
//2.创建代理类并且初始化代理对象
JDKProxy jdkp = new JDKProxy();
UserDao udiProxy = (UserDao)jdkp.newProxy(udi);//传目标对象,建立关联关系
//3.调用目标方法
int i = udiProxy.addUser("李四", 20);
System.out.println(i);
}
}
CGLIBProxy代理:
package cn.bdqn.aop.proxy.cglibProxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
* CGLIB
* 1.需要依赖于第三方jar包
* 2.不依赖目标类的接口
*
* JDK
* 1.不需要依赖于第三方jar包
* 2.目标类必须有相应的接口
*
* 执行效率:jdk.6之后,jdk动态代理效率>cglib动态代理
* SpringAOP 在目标类有实现接口的时候默认使用是jdk代理,没有实现接口使用cglib;
*
*/
//cglib代理类
public class CGLIBProxy implements MethodInterceptor{
private Object target;
public Object newProxy(Object obj){
this.target = obj;
//创建增强类
Enhancer enhancher = new Enhancer();
//设置生成代理类的父类为传入的目标类
enhancher.setSuperclass(target.getClass());
//设置回调方法为当前的对象;拦截器的回调方法
enhancher.setCallback(this);
//返回动态代理对象
return enhancher.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
check();
Object result = arg1.invoke(target, arg2);
return result;
}
//前置增强
private void check(){
System.out.println("cglib---执行检查--");
}
}
目标类UserDaoImpl:
不变,和jdk用法一样
Test:
package cn.bdqn.aop.proxy.cglibProxy;
import cn.bdqn.aop.proxy.dao.Impl.UserDaoImpl;
public class Test {
public static void main(String[] args) {
//创建目标类
UserDaoImpl udi = new UserDaoImpl();
//创建代理类
CGLIBProxy cglib = new CGLIBProxy();
//目标对象放进去
UserDaoImpl proxy = (UserDaoImpl)cglib.newProxy(udi);
int i = proxy.addUser("李四", 18);
System.out.println(i);
}
}
六、IoC和AOP扩展
1、注入的方式有三种
(1)、设置值注入
设置值注入就是HelloSpring中没有构造方法,实现输出hello,韩梅梅
(2)、构造注入
以HelloSpring 为例,在里面加入无参和有参构造方法,其他不变
在applicationcontext中重新配置hello后面输出要加的文字
输出hello,李雷
HelloSpring:
package cn.bdqn.ioc.helloSpring;
/*
* 1、设置值注入;依赖于属性的set方法
* 2、构造注入;依赖于构造方法
*/
public class HelloSpring {
private String who;
public HelloSpring(){
}
public HelloSpring(String who){
this.who = who;
}
public void print(){
System.out.println("hello:"+getWho());
}
public String getWho() {
return who;
}
public void setWho(String who) {
this.who = who;
}
}
配置文件applicationContext中:
<!-- 第二种注入方式:构造注入521 -->
<bean id="hello2" class="cn.bdqn.ioc.helloSpring.HelloSpring" >
<constructor-arg>
<value>李雷</value>
</constructor-arg>
</bean>
测试不变:
package cn.bdqn.ioc.helloSpring;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class HelloSpringTest {
@Test
public void test1(){
//1.加载Spring的配置文件,实例化Spring的上下文,此处就是控制权的反转
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.通过getBean的方法来获取指定<Bean>中id的实例
HelloSpring hs = (HelloSpring)context.getBean("hello");
hs.print();
}
}
另一实现,使用构造注入实现谁说了什么
输出lili说111
//LianXiSpring中也是加入有参和无参构造方法
package cn.bdqn.ioc.helloSpring;
public class LianXiSpring {
private String who;
private String say;
//加构造方法是为了构造注入
public LianXiSpring(){
}
public LianXiSpring(String who,String say){
this.say = say;
this.who = who;
}
public void print(){
System.out.println(getWho()+"说"+getSay());
}
public String getWho() {
return who;
}
public void setWho(String who) {
this.who = who;
}
public String getSay() {
return say;
}
public void setSay(String say) {
this.say = say;
}
}
配置文件中重新配置
<!-- 构造注入实现谁说了什么 -->
<bean id="lili" class="cn.bdqn.ioc.helloSpring.LianXiSpring">
<constructor-arg index="0">
<value>莉莉</value>
</constructor-arg>
<constructor-arg index="1">
<value>111</value>
</constructor-arg>
</bean>
测试
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
LianXiSpring lili = (LianXiSpring)context.getBean("lili");
lili.print();
}
(3)、p:命名空间注入
首先建pojo包,建立学生类,配置,测试
java
首先,学生类:设置三个属性,姓名,年龄,英文名,提供get/set方法
package cn.bdqn.ioc.pojo;
public class Student {
private String name;
private int age;
private String englishName;
//提供get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEnglishName() {
return englishName;
}
public void setEnglishName(String englishName) {
this.englishName = englishName;
}
}
配置文件,applicationContext
<bean id="student" class="cn.bdqn.ioc.pojo.Student" p:name="张三" p:age="18">
<property name="englishName">
<value><![CDATA[j&k]]></value>
</property>
</bean>
测试:
package cn.bdqn.ioc.helloSpring;
import org.junit.Test;
import cn.bdqn.ioc.pojo.Student;
public class StudentTest {
@Test
public void pTest(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = (Student)context.getBean("student");
//p空间注入
System.out.println(stu.getName()+"---"+stu.getAge());
System.out.println(stu.getEnglishName());
}
## 2、P命名空间下注入不同的数据类型
例如在学生类总注入其他类
### (1)、注入Bean类型
配置的时候有三种方法
#### ①、local是在当前文件找hello这个指定id的bean;—输出hello,
#### ②、bean用法表示在拆分后所有Spring中的配置文件中整体查找指定id的bean—输出hello,
#### ③、内部bean 输出hello,内部bean—输出hello,内部Bean
```java
首先学生类中:设置Bean类型属性,提供get/set方法
package cn.bdqn.ioc.pojo;
import cn.bdqn.ioc.helloSpring.HelloSpring;
public class Student {
//bean类型注入
private HelloSpring hs;
public HelloSpring getHs() {
return hs;
}
public void setHs(HelloSpring hs) {
this.hs = hs;
}
}
配置文件中:
<property name="hs">
<!-- 1、local是在当前文件找hello这个指定id的bean;
2、bean用法表示在拆分后所有Spring中的配置文件中整体查找指定id的bean
<ref bean="hello"/>
-->
<!--
<ref local="hello"/>
-->
<!-- 3、内部bean 输出hello,内部bean-->
<bean class="cn.bdqn.ioc.helloSpring.HelloSpring">
<property name="who">
<value>内部bean</value>
</property>
</bean>
</property>
测试:StudentTest public class StudentTest { @Test public void pTest(){ //bean类型注入 stu.getHs().print(); }
}
<a name="GL47R"></a>
### (2)、集合注入List/Set/Map/属性集合Properties
```java
学生类
public class Student {
//集合注入
private List<String> likeList;
//集合注入
private Set<String> likeSet;
//集合注入
private Map<String,String> likeMap;
//集合注入--属性集合
private Properties prop;
public Properties getProp() {
return prop;
}
public void setProp(Properties prop) {
this.prop = prop;
}
public Map<String, String> getLikeMap() {
return likeMap;
}
public void setLikeMap(Map<String, String> likeMap) {
this.likeMap = likeMap;
}
public Set<String> getLikeSet() {
return likeSet;
}
public void setLikeSet(Set<String> likeSet) {
this.likeSet = likeSet;
}
public List<String> getLikeList() {
return likeList;
}
public void setLikeList(List<String> likeList) {
this.likeList = likeList;
}
}
配置文件
<bean id="student" class="cn.bdqn.ioc.pojo.Student" p:name="张三" p:age="18">
<!-- 集合注入 -->
<property name="likeList">
<list>
<value>足球</value>
<value>篮球</value>
<value>羽毛球</value>
</list>
</property>
<property name="likeSet">
<set>
<value>游泳</value>
<value>健身</value>
</set>
</property>
<property name="likeMap">
<map>
<entry>
<key>
<value>football</value>
</key>
<value>足球</value>
</entry>
<entry>
<key>
<value>basketball</value>
</key>
<value>篮球</value>
</entry>
</map>
</property>
<!-- Properties集合注入 -->
<property name="prop">
<props>
<prop key="football">足球</prop>
<prop key="basketball">蓝球</prop>
</props>
</property>
</bean>
测试StudentTest:
public class StudentTest {
@Test
public void pTest(){
//list注入
System.out.println("-------List注入---------");
for (String s1 : stu.getLikeList()) {
System.out.print(s1+",");
}
//set注入
System.out.println();
System.out.println("-------Set注入---------");
for (String s1 : stu.getLikeSet()) {
System.out.print(s1+",");
}
//Map注入
System.out.println();
System.out.println("-------Map注入---------");
Map<String,String> map = stu.getLikeMap();
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry);
}
//Properties注入
System.out.println();
System.out.println("-------Properties注入---------");
Properties prop = stu.getProp();
Set<Entry<Object, Object>> propSet =prop.entrySet();
for (Entry<Object, Object> entry : propSet) {
System.out.println(entry.getKey()+"---"+entry.getValue());
}
}
}
(3)、注入空值和null值
package cn.bdqn.ioc.pojo;
//521、p命名空间注入
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import cn.bdqn.ioc.helloSpring.HelloSpring;
public class Student {
private String name;
private int age;
private String englishName;
//bean类型注入
private HelloSpring hs;
//集合注入
private List<String> likeList;
//集合注入
private Set<String> likeSet;
//集合注入
private Map<String,String> likeMap;
//集合注入--属性集合
private Properties prop;
//注入null或者空值
private String n1;//n1表示null
private String n2;//n2表示空
public String getN1() {
return n1;
}
public void setN1(String n1) {
this.n1 = n1;
}
public String getN2() {
return n2;
}
public void setN2(String n2) {
this.n2 = n2;
}
public Properties getProp() {
return prop;
}
public void setProp(Properties prop) {
this.prop = prop;
}
public Map<String, String> getLikeMap() {
return likeMap;
}
public void setLikeMap(Map<String, String> likeMap) {
this.likeMap = likeMap;
}
public Set<String> getLikeSet() {
return likeSet;
}
public void setLikeSet(Set<String> likeSet) {
this.likeSet = likeSet;
}
public List<String> getLikeList() {
return likeList;
}
public void setLikeList(List<String> likeList) {
this.likeList = likeList;
}
public HelloSpring getHs() {
return hs;
}
public void setHs(HelloSpring hs) {
this.hs = hs;
}
//提供get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEnglishName() {
return englishName;
}
public void setEnglishName(String englishName) {
this.englishName = englishName;
}
}
配置文件:
<!--第三种注入方式, p命名空间注入521 value中有特殊字符,需要转义 输出张三18和张三的英文名j&k-->
<bean id="student" class="cn.bdqn.ioc.pojo.Student" p:name="张三" p:age="18">
<property name="englishName">
<value><![CDATA[j&k]]></value>
</property>
<!-- 注入bean类型 输出hello-->
<property name="hs">
<!-- 1、local是在当前文件找hello这个指定id的bean;
2、bean用法表示在拆分后所有Spring中的配置文件中整体查找指定id的bean
<ref bean="hello"/>
-->
<!--
<ref local="hello"/>
-->
<!-- 3、内部bean 输出hello,内部bean-->
<bean class="cn.bdqn.ioc.helloSpring.HelloSpring">
<property name="who">
<value>内部bean</value>
</property>
</bean>
</property>
<!-- 集合注入 -->
<property name="likeList">
<list>
<value>足球</value>
<value>篮球</value>
<value>羽毛球</value>
</list>
</property>
<property name="likeSet">
<set>
<value>游泳</value>
<value>健身</value>
</set>
</property>
<property name="likeMap">
<map>
<entry>
<key>
<value>football</value>
</key>
<value>足球</value>
</entry>
<entry>
<key>
<value>basketball</value>
</key>
<value>篮球</value>
</entry>
</map>
</property>
<!-- Properties集合注入 -->
<property name="prop">
<props>
<prop key="football">足球</prop>
<prop key="basketball">蓝球</prop>
</props>
</property>
<!-- 注入null或者空值 -->
<property name="n1">
<null/>
</property>
<property name="n2">
<value></value>
</property>
</bean>
测试:
package cn.bdqn.ioc.helloSpring;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.bdqn.ioc.pojo.Student;
public class StudentTest {
@Test
public void pTest(){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = (Student)context.getBean("student");
//p空间注入
System.out.println(stu.getName()+"---"+stu.getAge());
System.out.println(stu.getEnglishName());
//bean类型注入
stu.getHs().print();
//list注入
System.out.println("-------List注入---------");
for (String s1 : stu.getLikeList()) {
System.out.print(s1+",");
}
//set注入
System.out.println();
System.out.println("-------Set注入---------");
for (String s1 : stu.getLikeSet()) {
System.out.print(s1+",");
}
//Map注入
System.out.println();
System.out.println("-------Map注入---------");
Map<String,String> map = stu.getLikeMap();
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry);
}
//Properties注入
System.out.println();
System.out.println("-------Properties注入---------");
Properties prop = stu.getProp();
Set<Entry<Object, Object>> propSet =prop.entrySet();
for (Entry<Object, Object> entry : propSet) {
System.out.println(entry.getKey()+"---"+entry.getValue());
}
//注入null或者空值
System.out.println("n1="+stu.getN1());
System.out.println("n2="+stu.getN2());
}
}
3、AOP扩展
(1)、前置增强 before
(2)、后置增强 afterReturning
首先、在aop—>dao—>UserDaoImpl中写入一个方法,抽接口,再收到Service相关中
其次,修改配置文件中插入日志的相关配置,修改切点
再在UserTest测试中,添加后置增强测试输出
再在配置文件内的前后插入日志中添加后置增强
最后在MyLogger中添加各种增强方法
1、此处的UserTest中,传入的id为1的时候,输出的是“张三”;
2、获得参数:MyLogger中://前置增强打印参数 Object[] args = jp.getArgs();log.info(“参数=”+Arrays.toString(args));
在UserTest中,运行getUserNameById方法,输出-参数=【1】
3、修改参数://前置增强无法修改参数,只能在环绕增强修改
4、进行后置操作,运行UserTest中的getUserNameById方法,实现在张三上面输出-后置增强,返回值=张三
5、修改参数,在MyLogger代理类中,写入环绕增强,先获取参数,再修改参数,args[0] = 100;;会将100传入id,实现输出 -后置增强,返回值=大聪明;下面输出 大聪明;
6、修改返回结果,再本来输出的大聪明后面加上‘真棒!’;
//修改返回结果 result = result+”真棒!”;
log.info(“后置增强,返回值=”+result); return result;
UserDaoImpl:
package cn.bdqn.aop.dao.Impl;
import cn.bdqn.aop.dao.UserDao;
public class UserDaoImpl implements UserDao{
public void addUser(){
System.out.println("---添加用户---");
}
//后置增强用到
public String getUserNameById(int id){
//伪代码
if(id == 1){
return "张三";
}else if(id == 2){
return "李四";
}else{
return "大聪明";
}
}
}
UserDao接口
package cn.bdqn.aop.dao;
public interface UserDao {
public void addUser();
public String getUserNameById(int id);
}
UserService接口:
package cn.bdqn.aop.service;
public interface UserService {
public void addUser();
public String getUserNameById(int id);
}
UserServiceImpl目标类
package cn.bdqn.aop.service.Impl;
import cn.bdqn.aop.dao.UserDao;
import cn.bdqn.aop.service.UserService;
//目标类---》实例化 ---》目标对象---》最终想执行目标方法addUSer(),
//执行方法之前想干别的事,还不行修改本处的代码/代理对象去调用执行目标方法
public class UserServiceImpl implements UserService{
//userDao 通过Spring IOC注入
private UserDao userDao;
public UserServiceImpl(){
}
public UserServiceImpl(UserDao userDao){
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
//调用dao层的addUser
public void addUser(){
userDao.addUser();
}
//后置增强用到
public String getUserNameById(int id){
return userDao.getUserNameById(id);
}
}
配置文件中修改切点
<!-- 定义切点 521修改,将括号前面的*换成UserDaoImpl中的方法名-->
<aop:pointcut expression="execution(* cn.bdqn.aop.service..*.getUserNameById(..))" id="pointcut"/>
测试中添加后置增强测试;只这一次,之后的增强方法都适用
package cn.bdqn.aop;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.bdqn.aop.service.UserService;
public class UserTest {
@Test
public void addUser(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us = (UserService)context.getBean("userService");
us.addUser();
}
//后置增强测试,通过获得名字方法传入id,获得姓名
@Test
public void getUserNameById(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService us = (UserService)context.getBean("userService");
//给下面的方法加前置后置
String name = us.getUserNameById(1);
//前置后置完成后才会输出下面的
System.out.println(name);
}
}
配置文件中添加后置增强
<!-- 前后插入日志 519-->
<bean id="myLogger" class="cn.bdqn.aop.logger.MyLogger"></bean>
<aop:config>
<!-- 定义切点 521修改,将括号前面的*换成UserDaoImpl中的方法名-->
<aop:pointcut expression="execution(* cn.bdqn.aop.service..*.getUserNameById(..))" id="pointcut"/>
<!-- 定义切面(切面等于切点加上增强方法) -->
<aop:aspect ref="myLogger">
<!-- 增强方式(前置,后置) -->
<!-- 前置增强 ,此处的方法名和myLogger中匹配的上就行 -->
<aop:before method="before" pointcut-ref="pointcut"/>
<!-- 后置增强 -->
<aop:after-returning method="afterReturning" returning="result" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
MyLogger代理类中
package cn.bdqn.aop.logger;
import java.beans.Expression;
import java.util.Arrays;
//代理类--》实例化---》代理对象--》调用执行目标方法,在执行之前完成相应的功能
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyLogger {
//日志输出
Logger log = Logger.getLogger(MyLogger.class);
//定义代理类---applicationContext.xml
//前置增强 JoinPoint连接点
public void before(JoinPoint jp){
//System.out.println("前置增强");
log.info("调用的"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法");
//前置增强打印参数
Object[] args = jp.getArgs();
args[0] = 100;
//前置增强可以获取参数,修改参数只能在环绕增强
log.info("参数="+Arrays.toString(args));
}
//后置增强
public void afterReturning(JoinPoint jp,Object result){
//做完事情要输出什么内容,并获得返回值
log.info("后置增强,返回值是"+result);
}
}
(3)、异常增强 afterThrowing
配置文件内加入:
<!-- 异常增强 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
MyLogger代理类中加入
//异常增强
public void afterThrowing(JoinPoint jp,Exception e){
System.out.println("异常增强"+e.getMessage());
}
(4)、环绕增强 around
环绕增强可以替代前置,后置,异常,和最终
,代理类中的around方法,不仅可以改变传入的id,还可以改变返回的结果
其他不变,在配置文件中加入环绕增强
<!-- 前后插入日志 519-->
<bean id="myLogger" class="cn.bdqn.aop.logger.MyLogger"></bean>
<aop:config>
<!-- 定义切点 521修改,将括号前面的*换成UserDaoImpl中的方法名-->
<aop:pointcut expression="execution(* cn.bdqn.aop.service..*.getUserNameById(..))" id="pointcut"/>
<!-- 定义切面(切面等于切点加上增强方法) -->
<aop:aspect ref="myLogger">
<!-- 增强方式(前置,后置) -->
<!-- 前置增强 ,此处的方法名和myLogger中匹配的上就行
<aop:before method="before" pointcut-ref="pointcut"/>
-->
<!-- 后置增强
<aop:after-returning method="afterReturning" returning="result" pointcut-ref="pointcut"/>
-->
<!-- 异常增强 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"/>
<!-- 环绕增强 -->
<aop:around method="around" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
MyLogger代理类中加入环绕增强
//环绕增强
public Object around(ProceedingJoinPoint pjp){
log.info("调用的"+ pjp.getTarget()+"的"+ pjp.getSignature().getName()+"方法");
Object[] args = pjp.getArgs();
log.info("参数="+Arrays.toString(args));
//修改后的参数,传入id位置,返回结果就是大聪明
args[0] = 100;
Object result = null;
try {
//执行目标方法
result = pjp.proceed(args);
} catch (Throwable e) {
//这里写代码就是异常增强
e.printStackTrace();
}finally{
//最终增强
}
//修改返回结果
result = result+"真棒!";
log.info("后置增强,返回值="+result);
return result;
}
}
(5)、最终增强 finally
配置文件中加入:
<!-- 最终增强 -->
<aop:after method="afterLogger" pointcut-ref="pointcut"/>
MyLogger代理类中
//最终增强
public void afterLogger(JoinPoint jp){
System.out.println(jp.getSignature().getName()+"方法结束执行");
}
七、使用注解实现IoC
1、IoC包下创建一个dao层,
创建Impl和PersonDao;抽接口;回到PersonDaoImpl中加入注解
再去配置文件,配置context:component-scan
再新建PersonTest,测试;
2、如果把注解中的 参数去掉,测试时getBean中传入方法所在类名,首字母小写。
3、注解:
@Component(“personDao”)——组件
@Repository————————用于标注dao类
@Service——————————用于标注业务类
@Controller————————-用于标注控制器(Servlect)下的类
Ioc下的dao层的PersonDaoImpl
package cn.bdqn.ioc.dao.Impl;
import org.springframework.stereotype.Repository;
import cn.bdqn.ioc.dao.PersonDao;
//使用注解实现IoC
//@Repository,相当于在配置文件中声明PersonDao,再去配置文件扫描指定包内的注解,使其生效
//如果注解中参数去掉,测试时getBean中传入方法所在类名,首字母小写;
@Repository
public class PersonDaoImpl implements PersonDao {
//模拟添加
public void addPerson(){
System.out.println("添加人员");
}
//抽接口
}
抽接口
package cn.bdqn.ioc.dao;
public interface PersonDao {
public void addPerson();
}
配置文件
<!-- 扫描指定包内的注解,使其生效 传接口中的地址也可,因为是自动扫描所有的注解523 -->
<context:component-scan base-package="cn.bdqn"></context:component-scan>
测试
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDao pd = (PersonDao)context.getBean("personDaoImpl");
pd.addPerson();
}
4、IoC下创建service包
创建Impl和PersonService接口
Impl中创建Bean类型属性 PersonDao;写一个addPerson的方法,personDao.addPerson();抽接口
配置文件,测试
加入@Service和@Autowired注解,代替配置文件中注入的过程
配置时不需要再重建,可直接在已有基础上,加上Service路径
PersonDaoImpl:
package cn.bdqn.ioc.service.Impl;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import cn.bdqn.ioc.dao.PersonDao;
import cn.bdqn.ioc.service.PersonService;
//@Service代替了Bean的声明
@Service("personService")
public class PersonServiceImpl implements PersonService {
/*@Autowired默认按照类型进行匹配,Spring提供的注解
* 如果发现类型相同的有多个,可用@Qualifer("personDaoImpl")进行名称定位,
* 哪个名称,是PersonDao这个bean的名称
* @Autowired代替配置文件中注入的过程
*
* @Resource默认按照名称进行匹配;java自带注解,JavaX包下的
* 如果没有找到相应的名称PersonDao,直接按类型查找
*/
@Resource
private PersonDao personDao;
public void addPerson(){
personDao.addPerson();
}
}
抽接口
package cn.bdqn.ioc.service;
public interface PersonService {
public void addPerson();
}
同上配置,查找路径归于一个cn.bdqn
测试:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService pd = (PersonService)context.getBean("personService");
pd.addPerson();
}
5、@Autowired和@Resoource注解的区别?
/*@Autowired默认按照类型进行匹配,Spring提供的注解
* 如果发现类型相同的有多个,可用 @Qualifer("personDaoImpl")进行名称定位,
哪个名称,是PersonDao这个bean的名称
@Autowired代替配置文件中注入的过程
@Resource默认按照名称进行匹配;java自带注解,JavaX包下的
如果没有找到相应的名称PersonDao,直接按类型查找
/
6、将Autowired换成Resource也好使;配置文件中的查找路径可以直接用cn.bdqn,匹配这个下的所有注解
八、使用注解实现AOP
在aop中创建MyLogger2代理类;加上@Aspect注解
在环绕增强上方加入注解@Around(),去除设置参数和修改结果
调用UserServiceImpl中的addUser方法,查看输出结果是否有“—调用**”
最后测试addUser方法