Spring
IOC / AOP
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:
●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
HelloSpring
package com.yrz.pojo;
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="com.yrz.pojo.Hello">
<property name="str" value="YRZ"/>
</bean>
</beans>
import com.yrz.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
IOC创建对象的方式
package com.yrz.pojo;
public class User {
private String name;
public User(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show() {
System.out.println("name="+name);
}
}
构造器注入
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.yrz.pojo.User">
<!--第一种:下标赋值-->
<constructor-arg index="0" value="yrz"/>
</bean>
<bean id="user" class="com.yrz.pojo.User">
<!--第二种:类型赋值(不建议使用)-->
<constructor-arg type="java.lang.String" value="yrz"/>
</bean>
<bean id="user" class="com.yrz.pojo.User">
<!--第三种:参数名赋值-->
<constructor-arg name="name" value="yrz"/>
</bean>
</beans>
import com.yrz.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
}
}
依赖注入之–Set注入(重点)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="address" class="com.yrz.pojo.Address">
<property name="address" value="上海"></property>
</bean>
<bean id="student" class="com.yrz.pojo.Student">
<!--第一种:普通注入-->
<property name="name" value="yrz"></property>
<!--第二种:bean注入,ref-->
<property name="address" ref="address"></property>
<!--数组-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>三国演义</value>
<value>水浒传</value>
</array>
</property>
<!--List-->
<property name="hobbys">
<list>
<value>听歌</value>
<value>打游戏</value>
<value>看电影</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="6531"></entry>
<entry key="学生证" value="1998"></entry>
</map>
</property>
<!--Set-->
<property name="game">
<set>
<value>LOL</value>
<value>COC</value>
</set>
</property>
<!--null-->
<property name="wife">
<null></null>
</property>
<!--properties-->
<property name="info">
<props>
<prop key="学号">132456</prop>
<prop key="性别">男</prop>
<prop key="名字">Y</prop>
</props>
</property>
</bean>
</beans>
注解自动装配
package com.yrz.pojo;
import org.springframework.beans.factory.annotation.Autowired;
public class People {
private String name;
@Autowired
private Cat cat;
@Autowired
private Dog dog;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "People{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
<context:annotation-config/>
<bean id="cat" class="com.yrz.pojo.Cat"></bean>
<bean id="dog" class="com.yrz.pojo.Dog"></bean>
<bean id="people" class="com.yrz.pojo.People"></bean>
</beans>
import com.yrz.pojo.People;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
People people = context.getBean("people", People.class);
people.getCat().shout();
people.getDog().shout();
}
}
在xml中开启注解的支持
<!--指定要扫描的包-->
<context:component-scan base-package="com.yrz.pojo"/>
<context:annotation-config/>
@Autowired:自动装配先通过类型,再通过名字
@Resource:自动装配先通过名字,再通过类型
@Qualifier:使用@Qualifier(value="")去配置@Autowired的使用
@Component(“user”):// 相当于配置文件中
–dao【@Repository】
–service【@Service】
–controller【@Controller】【@RestController】-- 不走视图层,返回字符串
@Scope:作用域
@Configuration:代表这是一个配置类,和beans.xml一样
@Bean:作用于方法上,相当于bean标签,id是方法名,class是返回值
@ComponentScan:扫描Component
@Aspect:标志这个类是一个切面
package com.yrz.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
//相当于配置文件中 <bean id="user" class="当前注解的类"/>
@Component
//作用域
@Scope("prototype")
public class User {
public String name;
//相当于 <property name = "name" value = "YRZ"/>
@Value("YRZ")
public void setName(String name) {
this.name = name;
}
}
静态代理模式
UserService
package com.yrz.demo02;
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
UserServiceImpl
package com.yrz.demo02;
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("add");
}
public void delete() {
System.out.println("delete");
}
public void update() {
System.out.println("update");
}
public void query() {
System.out.println("query");
}
}
UserServiceProxy
package com.yrz.demo02;
public class UserServiceProxy implements UserService{
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add() {
log("add");
userService.add();
}
public void delete() {
log("delete");
userService.delete();
}
public void update() {
log("update");
userService.update();
}
public void query() {
log("query");
userService.query();
}
public void log(String msg){
System.out.println("[Debug]使用了"+msg+"方法");
}
}
Client
package com.yrz.demo02;
public class Client {
public Client() {
}
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
}
}
动态代理模式
- 基于接口–JDK动态代理
了解两个类:
- Proxy–代理
- InvocationHandler–调用处理程序
ProxyInvocationHandler
package com.yrz.demo04;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInvocationHandler implements InvocationHandler {
//被代理的接口
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader()
,target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String msg){
System.out.println("使用了"+msg+"方法");
}
}
Client
package com.yrz.demo04;
import com.yrz.demo02.UserService;
import com.yrz.demo02.UserServiceImpl;
public class Client {
public static void main(String[] args) {
//真实角色
UserServiceImpl userService = new UserServiceImpl();
//代理角色,不存在
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);//设置要代理的对象
//动态生成代理类
UserService proxy = (UserService) pih.getProxy();
proxy.delete();
}
}
AOP实现方式一
使用原生Spring API接口(主要是Spring API接口实现)
package com.yrz.service;
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增");
}
public void delete() {
System.out.println("删");
}
public void update() {
System.out.println("改");
}
public void select() {
System.out.println("查");
}
}
package com.yrz.service;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
//method:要执行的目标对象方法
//args:参数
//target:目标
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了");
}
}
package com.yrz.service;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class AfterLog implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"方法,返回值结果为:"+returnValue);
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.yrz.service.UserServiceImpl"></bean>
<bean id="log" class="com.yrz.service.Log"></bean>
<bean id="afterLog" class="com.yrz.service.AfterLog"></bean>
<!--方式一:使用原生Spring API接口-->
<!--配置aop-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.yrz.service.UserServiceImpl.*(..))"/>
<!--执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"></aop:advisor>
</aop:config>
</beans>
import com.yrz.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
AOP实现方式二
使用自定义类来实现AOP(主要是切面定义)
package com.yrz.diy;
public class DiyPointCut {
public void before(){
System.out.println("========方法执行前========");
}
public void after(){
System.out.println("========方法执行后========");
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.yrz.service.UserServiceImpl"></bean>
<bean id="log" class="com.yrz.service.Log"></bean>
<bean id="afterLog" class="com.yrz.service.AfterLog"></bean>
<!--方式二:自定义类-->
<bean id="diy" class="com.yrz.diy.DiyPointCut"></bean>
<aop:config>
<!--自定义切面,ref要引用的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="point" expression="execution(* com.yrz.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
</beans>
AOP实现方式三
注解实现AOP
package com.yrz.diy;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect //标注这个类是一个切面
public class AnnotationPointCut {
@Before("execution(* com.yrz.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("执行前");
}
@After("execution(* com.yrz.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("执行后");
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.yrz.service.UserServiceImpl"></bean>
<bean id="log" class="com.yrz.service.Log"></bean>
<bean id="afterLog" class="com.yrz.service.AfterLog"></bean>
<!--方式三-->
<bean id="annotationPointCut" class="com.yrz.diy.AnnotationPointCut"></bean>
<!--开启注解支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>